5 lines
14 KiB
JSON
5 lines
14 KiB
JSON
{
|
|
"id": "guide/service-worker-communications",
|
|
"title": "Service worker communication",
|
|
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/service-worker-communications.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"service-worker-communication\">Service worker communication<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#service-worker-communication\"><i class=\"material-icons\">link</i></a></h1>\n<p>Importing <code><a href=\"api/service-worker/ServiceWorkerModule\" class=\"code-anchor\">ServiceWorkerModule</a></code> into your <code>AppModule</code> doesn't just register the service worker, it also provides a few services you can use to interact with the service worker and control the caching of your app.</p>\n<h4 id=\"prerequisites\">Prerequisites<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#prerequisites\"><i class=\"material-icons\">link</i></a></h4>\n<p>A basic understanding of the following:</p>\n<ul>\n<li><a href=\"guide/service-worker-getting-started\">Getting Started with Service Workers</a>.</li>\n</ul>\n<h2 id=\"swupdate-service\"><code><a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a></code> service<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#swupdate-service\"><i class=\"material-icons\">link</i></a></h2>\n<p>The <code><a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a></code> service gives you access to events that indicate when the service worker has discovered an available update for your app or when it has activated such an update—meaning it is now serving content from that update to your app.</p>\n<p>The <code><a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a></code> service supports four separate operations:</p>\n<ul>\n<li>Getting notified of <em>available</em> updates. These are new versions of the app to be loaded if the page is refreshed.</li>\n<li>Getting notified of update <em>activation</em>. This is when the service worker starts serving a new version of the app immediately.</li>\n<li>Asking the service worker to check the server for new updates.</li>\n<li>Asking the service worker to activate the latest version of the app for the current tab.</li>\n</ul>\n<h3 id=\"available-and-activated-updates\">Available and activated updates<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#available-and-activated-updates\"><i class=\"material-icons\">link</i></a></h3>\n<p>The two update events, <code>available</code> and <code>activated</code>, are <code>Observable</code> properties of <code><a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a></code>:</p>\n<code-example path=\"service-worker-getting-started/src/app/log-update.service.ts\" header=\"log-update.service.ts\" region=\"sw-update\">\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class LogUpdateService {\n\n constructor(updates: <a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a>) {\n updates.available.subscribe(event => {\n console.log('current version is', event.current);\n console.log('available version is', event.available);\n });\n updates.activated.subscribe(event => {\n console.log('old version was', event.previous);\n console.log('new version is', event.current);\n });\n }\n}\n\n</code-example>\n<p>You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date.</p>\n<h3 id=\"checking-for-updates\">Checking for updates<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#checking-for-updates\"><i class=\"material-icons\">link</i></a></h3>\n<p>It's possible to ask the service worker to check if any updates have been deployed to the server.\nThe service worker checks for updates during initialization and on each navigation request—that is, when the user navigates from a different address to your app.\nHowever, you might choose to manually check for updates if you have a site that changes frequently or want updates to happen on a schedule.</p>\n<p>Do this with the <code>checkForUpdate()</code> method:</p>\n<code-example path=\"service-worker-getting-started/src/app/check-for-update.service.ts\" header=\"check-for-update.service.ts\">\nimport { <a href=\"api/core/ApplicationRef\" class=\"code-anchor\">ApplicationRef</a>, <a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a> } from '@angular/core';\nimport { <a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a> } from '@angular/service-worker';\nimport { concat, interval } from 'rxjs';\nimport { first } from 'rxjs/operators';\n\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class CheckForUpdateService {\n\n constructor(appRef: <a href=\"api/core/ApplicationRef\" class=\"code-anchor\">ApplicationRef</a>, updates: <a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a>) {\n // Allow the app to stabilize first, before starting polling for updates with `interval()`.\n const appIsStable$ = appRef.isStable.pipe(first(isStable => isStable === true));\n const everySixHours$ = interval(6 * 60 * 60 * 1000);\n const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);\n\n everySixHoursOnceAppIsStable$.subscribe(() => updates.checkForUpdate());\n }\n}\n\n\n</code-example>\n<p>This method returns a <code>Promise</code> which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the <code>available</code> event will indicate availability of a new version of the app.</p>\n<div class=\"alert is-important\">\n<p>In order to avoid negatively affecting the initial rendering of the page, <code><a href=\"api/service-worker/ServiceWorkerModule\" class=\"code-anchor\">ServiceWorkerModule</a></code> waits for up to 30 seconds by default for the app to stabilize, before registering the ServiceWorker script.\nConstantly polling for updates, for example, with <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval\">setInterval()</a> or RxJS' <a href=\"https://rxjs.dev/api/index/function/interval\">interval()</a>, will prevent the app from stabilizing and the ServiceWorker script will not be registered with the browser until the 30 seconds upper limit is reached.</p>\n<p>Note that this is true for any kind of polling done by your application.\nCheck the <a href=\"api/core/ApplicationRef#isStable\">isStable</a> documentation for more information.</p>\n<p>You can avoid that delay by waiting for the app to stabilize first, before starting to poll for updates, as shown in the example above.\nAlternatively, you might want to define a different <a href=\"api/service-worker/SwRegistrationOptions#registrationStrategy\">registration strategy</a> for the ServiceWorker.</p>\n</div>\n<h3 id=\"forcing-update-activation\">Forcing update activation<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#forcing-update-activation\"><i class=\"material-icons\">link</i></a></h3>\n<p>If the current tab needs to be updated to the latest app version immediately, it can ask to do so with the <code>activateUpdate()</code> method:</p>\n<code-example path=\"service-worker-getting-started/src/app/prompt-update.service.ts\" header=\"prompt-update.service.ts\" region=\"sw-activate\">\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class PromptUpdateService {\n\n constructor(updates: <a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a>) {\n updates.available.subscribe(event => {\n if (promptUser(event)) {\n updates.activateUpdate().then(() => document.location.reload());\n }\n });\n }\n}\n\n</code-example>\n<div class=\"alert is-important\">\n<p>Calling <code>activateUpdate()</code> without reloading the page could break lazy-loading in a currently running app, especially if the lazy-loaded chunks use filenames with hashes, which change every version.\nTherefore, it is recommended to reload the page once the promise returned by <code>activateUpdate()</code> is resolved.</p>\n</div>\n<h3 id=\"handling-an-unrecoverable-state\">Handling an unrecoverable state<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#handling-an-unrecoverable-state\"><i class=\"material-icons\">link</i></a></h3>\n<p>In some cases, the version of the app used by the service worker to serve a client might be in a broken state that cannot be recovered from without a full page reload.</p>\n<p>For example, imagine the following scenario:</p>\n<ul>\n<li>A user opens the app for the first time and the service worker caches the latest version of the app.\nLet's assume the app's cached assets include <code>index.html</code>, <code>main.<main-hash-1>.js</code> and <code>lazy-chunk.<lazy-hash-1>.js</code>.</li>\n<li>The user closes the app and does not open it for a while.</li>\n<li>After some time, a new version of the app is deployed to the server.\nThis newer version includes the files <code>index.html</code>, <code>main.<main-hash-2>.js</code> and <code>lazy-chunk.<lazy-hash-2>.js</code> (note that the hashes are different now, because the content of the files has changed).\nThe old version is no longer available on the server.</li>\n<li>In the meantime, the user's browser decides to evict <code>lazy-chunk.<lazy-hash-1>.js</code> from its cache.\nBrowsers may decide to evict specific (or all) resources from a cache in order to reclaim disk space.</li>\n<li>The user opens the app again.\nThe service worker serves the latest version known to it at this point, namely the old version (<code>index.html</code> and <code>main.<main-hash-1>.js</code>).</li>\n<li>At some later point, the app requests the lazy bundle, <code>lazy-chunk.<lazy-hash-1>.js</code>.</li>\n<li>The service worker is unable to find the asset in the cache (remember that the browser evicted it).\nNor is it able to retrieve it from the server (since the server now only has <code>lazy-chunk.<lazy-hash-2>.js</code> from the newer version).</li>\n</ul>\n<p>In the above scenario, the service worker is not able to serve an asset that would normally be cached.\nThat particular app version is broken and there is no way to fix the state of the client without reloading the page.\nIn such cases, the service worker notifies the client by sending an <code><a href=\"api/service-worker/UnrecoverableStateEvent\" class=\"code-anchor\">UnrecoverableStateEvent</a></code> event.\nYou can subscribe to <code><a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a>#unrecoverable</code> to be notified and handle these errors.</p>\n<code-example path=\"service-worker-getting-started/src/app/handle-unrecoverable-state.service.ts\" header=\"handle-unrecoverable-state.service.ts\" region=\"sw-unrecoverable-state\">\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class HandleUnrecoverableStateService {\n constructor(updates: <a href=\"api/service-worker/SwUpdate\" class=\"code-anchor\">SwUpdate</a>) {\n updates.unrecoverable.subscribe(event => {\n notifyUser(\n `An error occurred that we cannot recover from:\\n${event.reason}\\n\\n` +\n 'Please reload the page.');\n });\n }\n}\n\n</code-example>\n<h2 id=\"more-on-angular-service-workers\">More on Angular service workers<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/service-worker-communications#more-on-angular-service-workers\"><i class=\"material-icons\">link</i></a></h2>\n<p>You may also be interested in the following:</p>\n<ul>\n<li><a href=\"guide/service-worker-devops\">Service Worker in Production</a>.</li>\n</ul>\n\n \n</div>\n\n<!-- links to this doc:\n - api/service-worker/SwUpdate\n - api/service-worker/UnrecoverableStateEvent\n - api/service-worker/UpdateActivatedEvent\n - api/service-worker/UpdateAvailableEvent\n - guide/service-worker-devops\n - guide/service-worker-getting-started\n - guide/service-worker-intro\n-->\n<!-- links from this doc:\n - api/core/ApplicationRef\n - api/core/ApplicationRef#isStable\n - api/core/Injectable\n - api/service-worker/ServiceWorkerModule\n - api/service-worker/SwRegistrationOptions#registrationStrategy\n - api/service-worker/SwUpdate\n - api/service-worker/UnrecoverableStateEvent\n - guide/service-worker-communications#available-and-activated-updates\n - guide/service-worker-communications#checking-for-updates\n - guide/service-worker-communications#forcing-update-activation\n - guide/service-worker-communications#handling-an-unrecoverable-state\n - guide/service-worker-communications#more-on-angular-service-workers\n - guide/service-worker-communications#prerequisites\n - guide/service-worker-communications#service-worker-communication\n - guide/service-worker-communications#swupdate-service\n - guide/service-worker-devops\n - guide/service-worker-getting-started\n - https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval\n - https://github.com/angular/angular/edit/master/aio/content/guide/service-worker-communications.md?message=docs%3A%20describe%20your%20change...\n - https://rxjs.dev/api/index/function/interval\n-->"
|
|
} |