Service Worker MDN英文筆記

Service worker concepts

Service workers essentially act as proxy servers that sit between web applications, the browser, and the network (when available).

A service worker is an event-driven worker registered against an origin and a path.A service worker is run in a worker context: it therefore has no DOM access, and runs on a different thread to the main JavaScript that powers your app, so it is not blocking. It is designed to be fully async; as a consequence, APIs such as synchronous XHR and localStorage can't be used inside a service worker.

Service worker register

ExamplesSection
The examples described here should be taken together to get a better understanding of how service workers scope applies to a page.

The following example uses the default value of scope (by omitting it). The service worker in this case will control example.com/index.html as well as pages underneath it, like example.com/product/description.html.

if ('serviceWorker' in navigator) {
  // Register a service worker hosted at the root of the
  // site using the default scope.
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('Service worker registration succeeded:', registration);
  }, /*catch*/ function(error) {
    console.log('Service worker registration failed:', error);
  });
} else {
  console.log('Service workers are not supported.');
}

note this is the file's URL relative to the origin, not the JS file that references it.

A single service worker can control many pages. Each time a page within your scope is loaded, the service worker is installed against that page and operates on it. Bear in mind therefore that you need to be careful with global variables in the service worker script: each page doesn’t get its own unique worker.

register

The following code, if included in a page at the root of a site, would apply to exactly the same pages as the example above. Remember the scope, when included, uses the page's location as its base. Alternatively, if this code were included in a page at example.com/product/description.html, the scope of './' would mean that the service worker only applies to resources under example.com/product. If I needed to register a service worker on example.com/product/description.html that applied to all of example.com, I would leave off the scope as above.

if ('serviceWorker' in navigator) {
  // Register a service worker hosted at the root of the
  // site using a more restrictive scope.
  navigator.serviceWorker.register('/sw.js', {scope: './'}).then(function(registration) {
    console.log('Service worker registration succeeded:', registration);
  }, /*catch*/ function(error) {
    console.log('Service worker registration failed:', error);
  });
} else {
  console.log('Service workers are not supported.');
}

If your server worker is active on a client being served with the Service-Worker-Allowed header, you can specify a list of max scopes for that worker.

Note: localStorage works in a similar way to service worker cache, but it is synchronous, so not allowed in service workers.

Note: IndexedDB can be used inside a service worker for data storage if you require it.

Download, install and activate

  1. Download

The service worker is immediately downloaded when a user first accesses a service worker–controlled site/page.

After that, it is downloaded every 24 hours or so. It may be downloaded more frequently, but it must be downloaded every 24 hours to prevent bad scripts from being annoying for too long.

  1. Install

Installation is attempted when the downloaded file is found to be new — either different to an existing service worker (byte-wise compared), or the first service worker encountered for this page/site.

You can listen out for the InstallEvent; a standard action is to prepare your service worker for usage when this fires, for example by creating a cache using the built in storage API, and placing assets inside it that you'll want for running your app offline.

  1. Activate

If there is an existing service worker available, the new version is installed in the background, but not yet activated — at this point it is called the worker in waiting. It is only activated when there are no longer any pages loaded that are still using the old service worker. As soon as there are no more pages to be loaded, the new service worker activates (becoming the active worker). Activation can happen sooner using ServiceWorkerGlobalScope.skipWaiting() and existing pages can be claimed by the active worker using Clients.claim().

There is also an activate event. The point where this event fires is generally a good time to clean up old caches and other things associated with the previous version of your service worker.

Your service worker can respond to requests using the FetchEvent event. You can modify the response to these requests in any way you want, using the FetchEvent.respondWith method.

Because oninstall/onactivate could take a while to complete, the service worker spec provides a waitUntil method, once this is called oninstall or onactivate, it passes a promise. Functional events are not dispatched to the service worker until the promise is successfully resolved.

use case ideas

  • Background data synchronization.
  • Responding to resource requests from other origins.
  • Receiving centralized updates to expensive-to-calculate data such as geolocation or gyroscope, so multiple pages can make use of one set of data.
    Client-side compiling and dependency management of CoffeeScript, less, CJS/AMD modules, etc. for development purposes.
    Hooks for background services.
  • Custom templating based on certain URL patterns.
  • Performance enhancements, for example pre-fetching resources that the user is likely to need in the near future, such as the next few pictures in a photo album.

Basic architecture

With service workers, the following steps are generally observed for basic set up:

  1. The service worker URL is fetched and registered via serviceWorkerContainer.register().
  2. If successful, the service worker is executed in a ServiceWorkerGlobalScope; this is basically a special kind of worker context, running off the main script execution thread, with no DOM access.
  3. The service worker is now ready to process events.
  4. Installation of the worker is attempted when service worker-controlled pages are accessed subsequently. An Install event is always the first one sent to a service worker (this can be used to start the process of populating an IndexedDB, and caching site assets). This is really the same kind of procedure as installing a native or Firefox OS app — making everything available for use offline.
  5. When the oninstall handler completes, the service worker is considered installed.
  6. Next is activation. When the service worker is installed, it then receives an activate event. The primary use of onactivate is for cleanup of resources used in previous versions of a Service worker script.
  7. The Service worker will now control pages, but only those opened after the register() is successful. i.e. a document starts life with or without a Service worker and maintains that for its lifetime. So documents will have to be reloaded to actually be controlled.
過(guò)程
事件

live demo

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(caches.match(event.request).then(function(response) {
    // caches.match() always resolves
    // but in case of success response will have value
    if (response !== undefined) {
      return response;
    } else {
      return fetch(event.request).then(function (response) {
        // response may be used only once
        // we need to save clone to put one copy in cache
        // and serve second one
        let responseClone = response.clone();
        
        caches.open('v1').then(function (cache) {
          cache.put(event.request, responseClone);
        });
        return response;
      }).catch(function () {
        return caches.match('/sw-test/gallery/myLittleVader.jpg');
      });
    }
  }));
});

event

fetch
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(resp) {
      return resp || fetch(event.request).then(function(response) {
        let responseClone = response.clone();
        caches.open('v1').then(function(cache) {
          cache.put(event.request, responseClone);
        });

        return response;
      });
    }).catch(function() {
      return caches.match('/sw-test/gallery/myLittleVader.jpg');
    })
  );
});

Cloning the response is necessary because request and response streams can only be read once. In order to return the response to the browser and put it in the cache we have to clone it. So the original gets returned to the browser and the clone gets sent to the cache. They are each read once.

  • activate
self.addEventListener('activate', function(event) {
  var cacheKeeplist = ['v2'];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheKeeplist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});

Developer toolsSection

Chrome has chrome://inspect/#service-workers, which shows current service worker activity and storage on a device, and chrome://serviceworker-internals, which shows more detail and allows you to start/stop/debug the worker process. In the future they will have throttling/offline modes to simulate bad or non-existent connections, which will be a really good thing.

articles

https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register

https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌做粤,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糟趾,死亡現(xiàn)場(chǎng)離奇詭異洗做,居然都是意外死亡燎竖,警方通過(guò)查閱死者的電腦和手機(jī)楼入,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)哥捕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人嘉熊,你說(shuō)我怎么就攤上這事遥赚。” “怎么了阐肤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵凫佛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我泽腮,道長(zhǎng)御蒲,這世上最難降的妖魔是什么衣赶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任诊赊,我火速辦了婚禮,結(jié)果婚禮上府瞄,老公的妹妹穿的比我還像新娘碧磅。我一直安慰自己,他們只是感情好遵馆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布鲸郊。 她就那樣靜靜地躺著,像睡著了一般货邓。 火紅的嫁衣襯著肌膚如雪秆撮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天换况,我揣著相機(jī)與錄音职辨,去河邊找鬼。 笑死戈二,一個(gè)胖子當(dāng)著我的面吹牛舒裤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播觉吭,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼腾供,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起伴鳖,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤节值,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后榜聂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體察署,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年峻汉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贴汪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡休吠,死狀恐怖扳埂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瘤礁,我是刑警寧澤阳懂,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站柜思,受9級(jí)特大地震影響岩调,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赡盘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一号枕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陨享,春花似錦葱淳、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至定硝,卻和暖如春皿桑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔬啡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工诲侮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人星爪。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓浆西,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親顽腾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子近零,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,334評(píng)論 0 10
  • The Inner Game of Tennis W Timothy Gallwey Jonathan Cape ...
    網(wǎng)事_79a3閱讀 12,077評(píng)論 3 20
  • 怎么到我這的感情都那么奇怪诺核,,我也是想不通的久信。遇到的一個(gè)比一個(gè)奇葩窖杀。這樣又能怎么講,只會(huì)讓我更郁悶裙士。嗯入客,更郁悶。我...
    小方框閱讀 137評(píng)論 0 0
  • 來(lái)大學(xué)第一次考試南用,先考了英語(yǔ)膀钠,然后是c語(yǔ)言,怎么說(shuō)呢裹虫,跟高中非常不同的感覺(jué)肿嘲。首先,因?yàn)橹皩W(xué)習(xí)階段完全沒(méi)有過(guò)...
    有情懷的女漢子閱讀 174評(píng)論 0 1