æ¬ææ¯å ³äºä½¿ç¨ service worker çæç¨ï¼å æ¬è®²è§£ service worker çåºæ¬æ¶æãæä¹æ³¨å service workerãæ°ç service worker çå®è£ ä»¥åæ¿æ´»çè¿ç¨ãæä¹æ´æ° service worker è¿æå®çç¼åæ§å¶åèªå®ä¹ååºï¼è¿ä¸åé½å¨ä¸ä¸ªç®åç离线çåºç¨ç¨åºä¸ã
Service worker çèæ¯æä¸ä¸ªå°æ° web ç¨æ·å¤å¹´çé¾é¢ââ丢失ç½ç»è¿æ¥ãå³ä½¿æ¯ä¸ç䏿好ç web appï¼å¦æä¸è½½ä¸äºå®ï¼ä¹æ¯é常ç³ç³çä½éªãå¦ä»è½ç¶å·²ç»æåç§å°è¯æ¥åé ææ¯å»å°è¯çè§£å³è¿ä¸ªé®é¢ï¼å¹¶ä¸å ¶ä¸ä¸äºé®é¢å·²ç»è¢«è§£å³ã使¯ï¼æéè¦çé®é¢æ¯ï¼ä»ç¶æ²¡æä¸ä¸ªå¥½çç»ç¹æºå¶å¯¹èµæºç¼ååèªå®ä¹çç½ç»è¯·æ±è¿è¡æ§å¶ã
Service worker ä¿®å¤äºè¿ä¸ªé®é¢ãä½¿ç¨ service workerï¼ä½ å¯ä»¥å° app 设置为é¦å 使ç¨ç¼åèµæºï¼ä»èå³ä½¿å¨ç¦»çº¿ç¶æï¼ä¹å¯ä»¥æä¾é»è®¤çä½éªï¼ç¶åä»ç½ç»è·åæ´å¤æ°æ®ï¼é常称为â离线ä¼å âï¼ãè¿å·²ç»å¨åç app ä¸å¯ç¨ï¼è¿æ¯ç»å¸¸éæ©åç appï¼è䏿¯éæ© web app ç主è¦åå ä¹ä¸ã
service worker çåè½ç±»ä¼¼äºä»£çæå¡å¨ï¼å è®¸ä½ å»ä¿®æ¹è¯·æ±åååºï¼å°å ¶æ¿æ¢ææ¥èªå ¶èªèº«ç¼åç项ç®ã
ä½¿ç¨ service worker çåå¤å·¥ä½service worker å¨ç°ä»£æµè§å¨ä¸é»è®¤å¼å¯ãè¦ä½¿ç¨ service worker è¿è¡ä»£ç ï¼ä½ éè¦éè¿ HTTPS æä¾ä½ ç代ç ââåºäºå®å
¨åå ï¼Service worker ä»
éå¨ HTTPS ä¸è¿è¡ãæ¯æ HTTPS çæå¡å¨æ¯å¿
è¦çãä¸ºäºæç®¡å®éªä»£ç ï¼ä½ å¯ä»¥ä½¿ç¨ GithubãNetlifyãVercel çæå¡ã为äºä¿è¿æ¬å°å¼åï¼æµè§å¨ä¹è®¤ä¸º localhost
æ¯ä¸ä¸ªå®å
¨çæ¥æºã
é常éµå¾ªä»¥ä¸åºæ¬æ¥éª¤æ¥ä½¿ç¨ service workerï¼
serviceWorkerContainer.register()
æ¥æ³¨åã妿æåï¼service worker å°å¨ ServiceWorkerGlobalScope
䏿§è¡ï¼è¿æ¬è´¨ä¸æ¯ä¸ç§ç¹æ®çä¸ä¸æï¼å¨ä¸»èæ¬æ§è¡çº¿ç¨ä¹å¤è¿è¡ï¼æ²¡æè®¿é® DOM çæéãService Worker ç°å¨å·²ä¸ºå¤çäºä»¶å好åå¤ãinstall
äºä»¶å§ç»æ¯åéç» service worker ç第ä¸ä¸ªäºä»¶ï¼è¿å¯ç¨äºå¯å¨å¡«å
IndexedDB åç¼åç«ç¹èµæºçè¿ç¨ï¼ã卿¤æ¥éª¤æé´ï¼åºç¨ç¨åºæ£å¨ä¸ºç¦»çº¿å¯ç¨ååå¤ãinstall
ç¨åºå¤ç宿æ¶ï¼service worker 被è§ä¸ºå·²å®è£
ãæ¤æ¶ï¼service worker çå
åçæ¬å¯è½å¤äºæ¿æ´»çç¶æå¹¶æ§å¶çæå¼ç页é¢ãç±äºæä»¬ä¸å¸æåä¸ service worker ç两个ä¸åçæ¬åæ¶è¿è¡ï¼å æ¤æ°çæ¬å°æªæ¿æ´»ãactivate
äºä»¶ãactivate
ç主è¦ç¨éæ¯å»æ¸
ç service worker ä¹åçæ¬ä½¿ç¨çèµæºãæ°ç service worker å¯ä»¥è°ç¨ skipWaiting()
è¦æ±ç«å³æ¿æ´»ï¼èæ éè¦æ±æå¼ç页é¢å
³éãç¶åï¼æ°ç service worker å°ç«å³æ¶å° activate
äºä»¶ï¼å¹¶å°æ¥ç®¡ä»»ä½æå¼ç页é¢ãregister()
æååæå¼ç页é¢ãæ¢å¥è¯è¯´ï¼ææ¡£å¿
须鿰å è½½æè½çæ£çåå°æ§å¶ï¼å ä¸ºææ¡£å¨ææè
没æ service worker çæ
åµä¸å¼å§åå¨ï¼å¹¶å¨å
¶çå½å¨æå
ç»´æ¤å®ã为äºè¦ç次é»è®¤è¡ä¸ºå¹¶å¨é¡µé¢æå¼çæ
åµä¸ï¼service worker å¯ä»¥è°ç¨ clients.claim()
æ¹æ³ã以䏿¯å¯ç¨ç service worker äºä»¶çæè¦ï¼
æ¼ç¤ºä¸ºäºå±ç¤ºæ³¨ååå®è£
service worker çåºç¡ç¥è¯ï¼æä»¬å·²ç»å建äºä¸ä¸ªå为ç®å service worker çæ¼ç¤ºï¼è¿æ¯ä¸ä¸ªä¹é«çæç大æå¾ååºãå®ä½¿ç¨ promise 驱å¨ç彿°ä» JSON 对象读åå¾åæ°æ®ï¼å¹¶ä½¿ç¨ fetch()
å è½½å¾åï¼ç¶åå°å¾åæ¾ç¤ºå¨é¡µé¢çä¸ä¸è¡ãæä»¬ææ¶è®©å®ä¿æä¸åãå®åæ¶ä¹æ³¨åãå®è£
åæ¿æ´» service workerã
ä½ ä¹å¯ä»¥å¨ GitHub 䏿¥çæºä»£ç 以åç®å service worker çå¨çº¿æ¼ç¤ºã
注åä½ ç worker卿们 app ç JavaScript æä»¶ï¼app.js
ï¼ç第ä¸ä¸ªä»£ç åä¸å¦ä¸æç¤ºãè¿æ¯æä»¬ä½¿ç¨ service worker çå
¥å£ç¹ã
const registerServiceWorker = async () => {
if ("serviceWorker" in navigator) {
try {
const registration = await navigator.serviceWorker.register("/sw.js", {
scope: "/",
});
if (registration.installing) {
console.log("æ£å¨å®è£
Service worker");
} else if (registration.waiting) {
console.log("å·²å®è£
Service worker installed");
} else if (registration.active) {
console.log("æ¿æ´» Service worker");
}
} catch (error) {
console.error(`注å失败ï¼${error}`);
}
}
};
// â¦
registerServiceWorker();
if
代ç åè¿è¡ç¹æ§æ£æµæµè¯ï¼ä»¥ç¡®ä¿å¨å°è¯æ³¨å service worker ä¹åï¼è¯¥ç¹æ§æ¯è¢«æ¯æçãServiceWorkerContainer.register()
彿°æ¥æ³¨åç«ç¹ç service workerãservice worker 代ç åªæ¯ä¸ä¸ªé©»ç卿们ç app å
çä¸ä¸ª JavaScript æä»¶ï¼æ³¨æï¼è¿ä¸ªæä»¶ç URL æ¯ç¸å¯¹äºæºï¼originï¼çï¼è䏿¯ç¸å¯¹äºå¼ç¨å®çé£ä¸ª JS æä»¶ï¼ãscope
åæ°æ¯å¯éçï¼å¹¶ä¸å¯ä»¥ç¨æ¥æå®ä½ æ³è¦ service worker æ§å¶çåä½ç¨åãå¨è¿ä¸ªä¾åä¸ï¼æä»¬æå®äº '/'
ï¼å
¶è¡¨ç¤º app çæºï¼originï¼ä¸çææå
容ãå¦æä½ ç空çè¯ï¼å®çé»è®¤å¼ä¹æ¯è¿ä¸ªï¼ä½æ¯æä»¬å¨è¿éæå®å®æ¯ä¸ºäºæ´æç¡®çéè¿°æä»¬çç®çãè¿å°±æ³¨åäºä¸ä¸ª service workerï¼å®å·¥ä½å¨ worker ä¸ä¸æï¼æä»¥æ²¡æè®¿é® DOM çæéã
å个 service worker å¯ä»¥æ§å¶å¾å¤é¡µé¢ãæ¯ä¸ªä½ çä½ç¨åï¼scopeï¼éç页é¢å è½½å®çæ¶åï¼å®è£ å¨é¡µé¢ç service worker å°±å¯ä»¥æ§å¶å®ãç¢è®°ä½ éè¦å°å¿ service worker èæ¬éçå ¨å±åéï¼æ¯ä¸ªé¡µé¢ä¸ä¼æèªå·±ç¬æç workerã
夿³¨ï¼ å ³äº service worker ä¸ä¸ªå¾æ£çäºæ å°±æ¯ï¼å¦æä½ åæä»¬ä¸é¢åç飿 ·ä½¿ç¨ç¹æ§æ£æµï¼åç°æµè§å¨å¹¶ä¸æ¯æ service workerï¼ä½æ¯å®è¿æ¯å¯ä»¥æ£å¸¸å°ä»¥é¢æçæ¹å¼å¨çº¿ä½¿ç¨ä½ ç appã
为ä»ä¹æç service worker 注å失败äºï¼å¯è½æ¯å¦ä¸çåå ï¼
https://mdn.github.io/sw-test/sw.js
ï¼app çæ ¹ç®å½æ¯ https://mdn.github.io/sw-test/
ã使¯è·¯å¾éè¦åæ /sw.js
ãsw.js
ä½äº /js/sw.js
ä¸ï¼é»è®¤æ
åµä¸å®åªè½æ§å¶ /js/
ä¸ç URLï¼ãå¯ä»¥ä½¿ç¨ Service-Worker-Allowed
æ 头æå® worker çæå¤§ä½ç¨åå表ãå¨ä½ ç service worker 注åä¹åï¼æµè§å¨ä¼å°è¯ä¸ºä½ ç页颿ç«ç¹å®è£ å¹¶æ¿æ´»å®ã
install
äºä»¶ä¼å¨æ³¨åæå宿ä¹å触åãinstall
äºä»¶é常ä¼è¿æ ·ç¨ï¼å°ç¦»çº¿è¿è¡ app 产ççèµæºæ¾ç½®å¨æµè§å¨ç¦»çº¿ç¼åç空é´ã为äºå®ç°è¿ä¸ªï¼æä»¬ä½¿ç¨äº Service Worker çåå¨ APIââcache
ââä¸ä¸ª service worker ä¸çå
¨å±å¯¹è±¡ï¼å®ä½¿æä»¬å¯ä»¥åå¨ç½ç»ååºåæ¥çèµæºï¼å¹¶ä¸æ ¹æ®å®ä»¬çè¯·æ±æ¥çæ keyãè¿ä¸ª API åæµè§å¨çæ åçç¼åå·¥ä½åçå¾ç¸ä¼¼ï¼ä½å®ç¹å®äºä½ çåçãç´å°ä½ æ¸
çå®ä»¬ä¹åï¼è¿äºå
容é½ä¼æä¹
åå¨ã
以䏿¯æä»¬ç service worker å¦ä½å¤ç install
äºä»¶ï¼
const addResourcesToCache = async (resources) => {
const cache = await caches.open("v1");
await cache.addAll(resources);
};
self.addEventListener("install", (event) => {
event.waitUntil(
addResourcesToCache([
"/",
"/index.html",
"/style.css",
"/app.js",
"/image-list.js",
"/star-wars-logo.jpg",
"/gallery/bountyHunters.jpg",
"/gallery/myLittleVader.jpg",
"/gallery/snowTroopers.jpg",
]),
);
});
install
äºä»¶çå¬å¨å»çå¬ service workerï¼è¿éæçæ¯ self
ï¼ï¼æ¥çå¨äºä»¶ä¸è°ç¨ ExtendableEvent.waitUntil()
æ¹æ³ââè¿ä¼ç¡®ä¿ Service Worker ä¸ä¼å¨ waitUntil()
éé¢çä»£ç æ§è¡å®æ¯ä¹åå®è£
宿ãaddResourcesToCache()
å
ï¼æä»¬ä½¿ç¨äº caches.open()
æ¹æ³æ¥å建äºå«å v1
çæ°ç¼åï¼è¿å°ä¼æ¯æä»¬çç«ç¹èµæºç¼åç第 1 ä¸ªçæ¬ãç¶åæä»¬ä¼å¨å建çç¼å示ä¾ä¸è°ç¨ addAll()
彿°ï¼å®çåæ°éç¨ä¸ä¸ª URL æ°ç»ï¼æåä½ æ³è¦ç¼åçææèµæºãå
¶ä¸ï¼URL æ¯ç¸å¯¹äº worker ç locationã夿³¨ï¼ Web Storage APIï¼localStorage
ï¼è· service worker ç cache å·¥ä½åçåå类似ï¼ä½æ¯å®æ¯åæ¥çï¼æä»¥ä¸å
è®¸å¨ service worker ä¸ä½¿ç¨ã
夿³¨ï¼ å¦æä½ éè¦çè¯ï¼å¯ä»¥å¨ service worker ä¸ä½¿ç¨ IndexedDB æ¥åæ°æ®åå¨ã
èªå®ä¹è¯·æ±çååºç°å¨ä½ å·²ç»å°ä½ çç«ç¹èµæºç¼åäºï¼ä½ éè¦åè¯ service worker 让å®ç¨è¿äºç¼åå
容æ¥åç¹ä»ä¹ãæäº fetch
äºä»¶ï¼è¿æ¯å¾å®¹æåå°çã
æ¯æ¬¡è·å service worker æ§å¶çèµæºæ¶ï¼é½ä¼è§¦å fetch
äºä»¶ï¼è¿äºèµæºå
æ¬äºæå®çä½ç¨åå
çææ¡£ï¼åè¿äºææ¡£å
å¼ç¨çå
¶ä»ä»»ä½èµæºï¼æ¯å¦ index.html
åèµ·äºä¸ä¸ªè·¨æºçè¯·æ±æ¥åµå
¥ä¸ä¸ªå¾çï¼è¿ä¸ªä¹ä¼éè¿ service workerï¼ã
ä½ å¯ä»¥ç» service worker æ·»å ä¸ä¸ª fetch
çäºä»¶çå¬å¨ï¼æ¥çè°ç¨ event ä¸ç respondWith()
æ¹æ³æ¥å«ææä»¬ç HTTP ååºï¼ç¶åä½ ç¨å¯ä»¥ç¨èªå·±çæ¹æ³æ¥æ´æ°å®ä»¬ã
self.addEventListener("fetch", (event) => {
event.respondWith(/* å¨è¿éæ¾ç½®èªå®ä¹çå
容 */);
});
å¨ä»»ä½æ åµä¸ï¼æä»¬ä¼é¦å ååºç¼åç URL åç½ç»è¯·æ±ç URL ç¸å¹é çèµæºï¼
self.addEventListener("fetch", (event) => {
event.respondWith(caches.match(event.request));
});
caches.match(event.request)
å
许æä»¬å¯¹ç½ç»è¯·æ±éçæ¯ä¸ªèµæºä¸ç¼åéå¯è·åççæèµæºè¿è¡å¹é
ï¼æ¥çç¼å䏿¯å¦æç¸åºçèµæºã该å¹é
éè¿ URL ååç§æ 头è¿è¡ï¼å°±åæ£å¸¸ç HTTP 请æ±ä¸æ ·ã
å¨ service worker çç¼åä¸åå¨ç¸å¹é
çèµæºæ¶ï¼caches.match(event.request)
æ¯é常æ£çã使¯å¦ææ²¡æå¹é
èµæºå¢ï¼å¦ææä»¬ä¸æä¾ä»»ä½é误å¤çï¼promise å°±ä¼å
ç° undefined
ï¼å èæä»¬ä¸ä¼å¾å°ä»»ä½å
容ã
卿µè¯ç¼åçååºåï¼æä»¬å¯ä»¥éåå°å¸¸è§ç½ç»è¯·æ±ï¼
const cacheFirst = async (request) => {
const responseFromCache = await caches.match(request);
if (responseFromCache) {
return responseFromCache;
}
return fetch(request);
};
self.addEventListener("fetch", (event) => {
event.respondWith(cacheFirst(event.request));
});
å¦æèµæºä¸åå¨ç¼åä¸ï¼å®ä»¬åä¼ä»ç½ç»ä¸è¿è¡è¯·æ±ã
ä½¿ç¨æ´å¤æççç¥ï¼æä»¬ä¸ä» å¯ä»¥ä»ç½ç»ä¸è¯·æ±èµæºï¼è¿å¯ä»¥å°å ¶ä¿åå°ç¼åä¸ï¼ä»¥ä¾¿ç¨åå¯¹è¯¥èµæºç请æ±ä¹å¯ä»¥ç¦»çº¿æ£ç´¢ãè¿æå³çï¼å¦æå°é¢å¤çå¾åæ·»å å°æç大æå¾åºä¸ï¼æä»¬ç app å¯ä»¥èªå¨æåå¹¶ç¼åå®ä»¬ã以ä¸ç段å®ç°äºè¿æ ·ççç¥ï¼
const putInCache = async (request, response) => {
const cache = await caches.open("v1");
await cache.put(request, response);
};
const cacheFirst = async (request) => {
const responseFromCache = await caches.match(request);
if (responseFromCache) {
return responseFromCache;
}
const responseFromNetwork = await fetch(request);
putInCache(request, responseFromNetwork.clone());
return responseFromNetwork;
};
self.addEventListener("fetch", (event) => {
event.respondWith(cacheFirst(event.request));
});
å¦æè¯·æ± URL å¨ç¼åä¸ä¸å¯ç¨ï¼æä»¬å°ä½¿ç¨ await fetchï¼request)
ä»ç½ç»è¯·æ±ä¸è¯·æ±èµæºãä¹åï¼æä»¬å°ååºçå
éæ¾å
¥ç¼åãputInCache()
彿°ä½¿ç¨ caches.open('v1')
å cache.put()
å°èµæºå¢å å°ç¼åä¸ãå®çåå§ååºä¼è¿åç»æµè§å¨ä»¥æä¾ç»è°ç¨å®ç页é¢ã
å éååºæ¯å¿ è¦çï¼å 为请æ±åååºæµä» å¯ä»¥è¯»å䏿¬¡ã为äºè¿åååºå°æµè§å¨ï¼å¹¶å°å ¶æ¾å ¥ç¼åä¸ï¼æä»¬å¾å éå®ãå æ¤åå§çèµæºä¼è¿åç»æµè§å¨ï¼å éçèµæºä¼åéå°ç¼åãå®ä»¬é½åªè½è¢«è¯»å䏿¬¡ã
çèµ·æ¥æç¹å¥æªçæ¯ï¼putInCache()
è¿åç promise 并没æä½¿ç¨ awaitãä½åå æ¯ï¼æä»¬å¹¶ä¸æ³è¦çå°ç¼å被添å è³ç¼åååè¿åååºã
æä»¬ç°å¨å¯ä¸çé®é¢æ¯å½è¯·æ±æ²¡æå¹é å°ç¼åä¸çä»»ä½èµæºï¼æç½ç»ä¸å¯ç¨çæ¶ï¼æä»¬ç请æ±ä¾ç¶ä¼å¤±è´¥ã让æä»¬æä¾ä¸ä¸ªé»è®¤çåéæ¹æ¡ä»¥ä¾¿ä¸ç®¡åçäºä»ä¹ï¼ç¨æ·è³å°è½å¾å°äºä¸è¥¿ï¼
const putInCache = async (request, response) => {
const cache = await caches.open("v1");
await cache.put(request, response);
};
const cacheFirst = async ({ request, preloadResponsePromise, fallbackUrl }) => {
// é¦å
ï¼å°è¯ä»ç¼åä¸è·åèµæº
const responseFromCache = await caches.match(request);
if (responseFromCache) {
return responseFromCache;
}
// ç¶åå°è¯ä»ç½ç»ä¸è·åèµæº
try {
const responseFromNetwork = await fetch(request);
// ååºå¯è½ä¼è¢«ä½¿ç¨
// æä»¬éè¦å°å®çæ·è´æ¾å
¥ç¼å
// ç¶ååè¿å该ååº
putInCache(request, responseFromNetwork.clone());
return responseFromNetwork;
} catch (error) {
const fallbackResponse = await caches.match(fallbackUrl);
if (fallbackResponse) {
return fallbackResponse;
}
// å½åè½çååºä¹ä¸å¯ç¨æ¶ï¼
// æä»¬ä¾¿æ è½ä¸ºåäºï¼ä½æä»¬å§ç»éè¦
// è¿å Response 对象
return new Response("Network error happened", {
status: 408,
headers: { "Content-Type": "text/plain" },
});
}
};
self.addEventListener("fetch", (event) => {
event.respondWith(
cacheFirst({
request: event.request,
fallbackUrl: "/gallery/myLittleVader.jpg",
}),
);
});
æä»¬éæ©äºåè½çå¾çï¼å 为å¯ä¸çæ´æ°æ¯å¯¹æ°å¾ççï¼å®å¯è½ä¼å¤±è´¥ï¼å 为å
¶ä»çææå
容é½ä¾èµäºæä»¬ä¹åçå°ç install
äºä»¶çå¬å¨ä¸çå®è£
è¿ç¨ã
妿å¯ç¨äºå¯¼èªé¢å è½½åè½ï¼å ¶å°å¨ååº fetch 请æ±åï¼ç«å³å¼å§ä¸è½½èµæºï¼å¹¶åæ¶æ¿æ´» service workerãè¿ç¡®ä¿äºå¨å¯¼èªå°ä¸ä¸ªé¡µé¢æ¶ï¼ç«å³å¼å§ä¸è½½ï¼è䏿¯çå° service worker è¢«æ¿æ´»ãè¿ç§å»¶è¿åççæ¬¡æ°ç¸å¯¹è¾å°ï¼ä½æ¯ä¸æ¦åçå°±ä¸å¯é¿å ï¼èä¸å¯è½å¾éè¦ã
é¦å
ï¼å¿
é¡»å¨ service worker æ¿æ´»æé´ä½¿ç¨ registration.navigationPreload.enable()
æ¥å¯ç¨è¯¥åè½ï¼
self.addEventListener("activate", (event) => {
event.waitUntil(self.registration?.navigationPreload.enable());
});
ç¶åä½¿ç¨ event.preloadResponse
çå¾
é¢å è½½çèµæºå¨ fetch
äºä»¶å¤çç¨åºä¸å®æä¸è½½ã
ç»§ç»åå èç示ä¾ï¼æä»¬æå ¥ä»£ç ï¼ä»¥ä¾¿å¨ç¼åæ£æ¥åçå¾ é¢å è½½çèµæºï¼å¦æå¤±è´¥ï¼ååä»ç½ç»ä¸è·åã
æ°æµç¨æ¯ï¼
event.preloadResponse
ï¼å®ä½ä¸º preloadResponsePromise
ä¼ éç» cacheFirst()
彿°ã妿è¿åç»æï¼åç¼åå®ãconst addResourcesToCache = async (resources) => {
const cache = await caches.open("v1");
await cache.addAll(resources);
};
const putInCache = async (request, response) => {
const cache = await caches.open("v1");
await cache.put(request, response);
};
const cacheFirst = async ({ request, preloadResponsePromise, fallbackUrl }) => {
// é¦å
ï¼å°è¯ä»ç¼åä¸è·åèµæº
const responseFromCache = await caches.match(request);
if (responseFromCache) {
return responseFromCache;
}
// æ¥ä¸æ¥ï¼å°è¯ä½¿ç¨ç¼åæé¢å è½½çååº
const preloadResponse = await preloadResponsePromise;
if (preloadResponse) {
console.info("using preload response", preloadResponse);
putInCache(request, preloadResponse.clone());
return preloadResponse;
}
// ç¶åå°è¯ä»ç½ç»ä¸è·åèµæº
try {
const responseFromNetwork = await fetch(request);
// ååºå¯è½ä¼è¢«ä½¿ç¨
// æä»¬éè¦å°å®çæ·è´æ¾å
¥ç¼å
// ç¶ååè¿å该ååº
putInCache(request, responseFromNetwork.clone());
return responseFromNetwork;
} catch (error) {
const fallbackResponse = await caches.match(fallbackUrl);
if (fallbackResponse) {
return fallbackResponse;
}
// å½åè½çååºä¹ä¸å¯ç¨æ¶ï¼
// æä»¬ä¾¿æ è½ä¸ºåäºï¼ä½æä»¬å§ç»éè¦
// è¿å Response 对象
return new Response("Network error happened", {
status: 408,
headers: { "Content-Type": "text/plain" },
});
}
};
// å¯ç¨å¯¼èªé¢å è½½
const enableNavigationPreload = async () => {
if (self.registration.navigationPreload) {
await self.registration.navigationPreload.enable();
}
};
self.addEventListener("activate", (event) => {
event.waitUntil(enableNavigationPreload());
});
self.addEventListener("install", (event) => {
event.waitUntil(
addResourcesToCache([
"/",
"/index.html",
"/style.css",
"/app.js",
"/image-list.js",
"/star-wars-logo.jpg",
"/gallery/bountyHunters.jpg",
"/gallery/myLittleVader.jpg",
"/gallery/snowTroopers.jpg",
]),
);
});
self.addEventListener("fetch", (event) => {
event.respondWith(
cacheFirst({
request: event.request,
preloadResponsePromise: event.preloadResponse,
fallbackUrl: "/gallery/myLittleVader.jpg",
}),
);
});
注æï¼å¨æ¤ç¤ºä¾ä¸ï¼æ è®ºèµæºæ¯âæ£å¸¸âä¸è½½è¿æ¯é¢å è½½ï¼æä»¬é½ä¼ä¸è½½åç¼åç¸åçæ°æ®ãç¸åï¼ä½ å¯ä»¥éæ©å¨é¢å è½½æ¶ä¸è½½åç¼åå
¶ä»èµæºã请åé
NavigationPreloadManager
> èªå®ä¹ååº ä»¥äºè§£è¯¦æ
ã
å¦æä½ ç service worker å·²ç»è¢«å®è£ ï¼ä½æ¯å·æ°é¡µé¢æ¶æä¸ä¸ªæ°çæ¬çå¯ç¨ï¼æ°çç service worker ä¼å¨åå°å®è£ ï¼ä½æ¯ä»ç¶ä¸ä¼è¢«æ¿æ´»ãå½ä¸åæä»»ä½å·²å è½½ç页é¢å¨ä½¿ç¨æ§çç service worker çæ¶åï¼æ°çæ¬æä¼æ¿æ´»ã䏿¦å乿²¡æè¿æ ·çå·²å è½½ç页é¢ï¼æ°ç service worker å°±ä¼è¢«æ¿æ´»ã
夿³¨ï¼ å¯ä»¥éè¿ä½¿ç¨ Clients.claim()
ç»è¿è¿ä¸ç¹ã
ä½ æ³æä½ çæ°çç service worker éç install
äºä»¶çå¬å¨æ¹æä¸é¢è¿æ ·ï¼æ³¨ææ°ççæ¬å·ï¼ï¼
const addResourcesToCache = async (resources) => {
const cache = await caches.open("v2");
await cache.addAll(resources);
};
self.addEventListener("install", (event) => {
event.waitUntil(
addResourcesToCache([
"/",
"/index.html",
"/style.css",
"/app.js",
"/image-list.js",
// â¦
// å
嫿°çæ¬éè¦çå
¶ä»èµæºâ¦
]),
);
});
å½å®è£
åççæ¶åï¼åä¸ä¸ªçæ¬ä¾ç¶å¨ååºè¯·æ±ãæ°ççæ¬æ£å¨åå°å®è£
ãæä»¬è°ç¨äºä¸ä¸ªæ°çç¼å v2
ï¼æä»¥åä¸ä¸ª v1
çæ¬çç¼åä¸ä¼è¢«æ°ä¹±ã
彿²¡æé¡µé¢å¨ä½¿ç¨ä¹åççæ¬çæ¶åï¼è¿ä¸ªæ°ç service worker 就伿¿æ´»å¹¶å¼å§ååºè¯·æ±ã
å 餿§ç¼åæ£å¦æä»¬å¨æåä¸èçå°ç飿 ·ï¼å½ä½ æ´æ° service worker å°ä¸ä¸ªæ°ççæ¬ï¼ä½ å°å¨å®ç install
äºä»¶å¤çç¨åºä¸å建ä¸ä¸ªæ°çç¼åãå¨ä»æç±ä¸ä¸ä¸ª worker ççæ¬æ§å¶çæå¼ç页é¢ï¼ä½ å°±éè¦åæ¶ä¿çè¿ä¸¤ä¸ªçæ¬çç¼åï¼å 为ä¹åççæ¬éè¦å®ç¼åççæ¬ãä½ å¯ä»¥ä½¿ç¨ activate
äºä»¶ä»ä¹åçç¼åä¸ç§»é¤æ°æ®ã
ä¼ ç» waitUntil()
ç promise ä¼é»å¡å
¶ä»çäºä»¶ï¼ç´å°å®å®æï¼å æ¤ä½ å¯ä»¥æ¾å¿ï¼å½ä½ 卿°ç service worker ä¸å¾å°ä½ ç第ä¸ä¸ª fetch
äºä»¶æ¶ï¼ä½ çæ¸
çæä½å·²ç»å®æã
const deleteCache = async (key) => {
await caches.delete(key);
};
const deleteOldCaches = async () => {
const cacheKeepList = ["v2"];
const keyList = await caches.keys();
const cachesToDelete = keyList.filter((key) => !cacheKeepList.includes(key));
await Promise.all(cachesToDelete.map(deleteCache));
};
self.addEventListener("activate", (event) => {
event.waitUntil(deleteOldCaches());
});
å¼åè
å·¥å
·
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4