我將帶你快速熟悉一個pwa應用的基本使用css
本文中涉及到的內容:html
Fetch 提供了許多與XMLHttpRequest相同的功能,爲何要在這裏說起這個,由於在咱們在service worker環境中是不能去使用XMLHttpRequest對象的,故而這是一個很是重要的api。web
Fetch 的核心在於對 HTTP 接口的抽象,包括 Request,Response,Headers,Body這些接口面試
這裏只是簡單介紹shell
Promise<Response> fetch(input[, init]);
複製代碼
參數介紹:json
這是一個能夠緩存瀏覽器緩存的接口,離線應用的核心就靠他了api
name | 描述 |
---|---|
Cache.match(request, options) | 該方法會檢查是否存在該request的緩存,返回 Promise對象,resolve的結果是跟 Cache 對象匹配的第一個已經緩存的請求。 |
Cache.matchAll(request, options) | 同上,不一樣的是resolve的結果是跟Cache對象匹配的全部請求組成的數組。 |
Cache.add(request) | 抓取這個URL, 檢索並把返回的response對象添加到給定的Cache對象.這在功能上等同於調用 fetch(), 而後使用 Cache.put() 將response添加到cache中. |
Cache.addAll(requests) | 抓取一個URL數組,檢索並把返回的response對象添加到給定的Cache對象。 |
Cache.put(request, response) | 同時抓取一個請求及其響應,並將其添加到給定的cache。 |
Cache.delete(request, options) | 搜索key值爲request的Cache 條目。若是找到,則刪除該Cache 條目,而且返回一個resolve爲true的Promise對象;若是未找到,則返回一個resolve爲false的Promise對象。 |
Cache.keys(request, options) | 返回一個Promise對象,resolve的結果是Cache對象key值組成的數組。 |
options參數的解釋:數組
這是咱們要花時間最多的地方!promise
當你調用 navigator.serviceWorker.register 註冊一個新的 service worker ,service worker 代碼就會被下載、解析、進入installing階段。若安裝成功則進入installed,失敗則進入redundant瀏覽器
installed 狀態下的service worker會判斷本身是否已經被註冊過,若是是第一次註冊將進入activating狀態,若是發現本身被註冊且處於activated狀態,那麼將進入waiting狀態
此狀態下的sw將進入activated(必將進入activated狀態)
一旦 service worker 激活,它就準備好接管頁面並監聽功能性事件了(例如 fetch 事件)
當sw註冊失敗或者被新的sw替換將進入此狀態(只有這兩種狀況會進入redundant)
頁面中的代碼:
if("serviceWorker" in navigator){
window.onload = function(){
navigator.serviceWorker.register("./sw.js").then((registration)=>{
var sw = null, state;
if(registration.installing) {
sw = registration.installing;
state = 'installing';
} else if(registration.waiting) {
sw = registration.waiting;
state = 'installed'
} else if(registration.active) {
sw = registration.active;
state = 'activated'
}
state && console.log(`sw state is ${state}`);
if(sw) {
sw.onstatechange = function() {
console.log(`sw state is ${sw.state}`);
}
}
}).catch(()=>{
console.log('sw fail');
})
}
}
複製代碼
sw.js:
self.addEventListener('install',function () {
console.log('install callback');
})
self.addEventListener('activate',function () {
console.log('activate callback');
})
self.addEventListener('fetch',function () {
console.log('fetch callback');
})
複製代碼
首次刷新頁面控制檯輸出:
install callback
sw state is installing
sw state is installed
activate callback
sw state is activating
sw state is activated
複製代碼
再次刷新頁面控制檯輸出:
sw state is activated
fetch callback
複製代碼
install,與active事件僅僅執行一次,fetch在首次刷新也面試時是不請求的
當更新sw時,刷新頁面,此時:
代碼此處能夠本身嘗試
waitUntil函數傳入promise做爲參數,當promise執行完成纔會接着往下走。
1.加入成功的回調:
self.addEventListener('install',function (event) {
event.waitUntil(new Promise(function(resolve) {
setTimeout(() => {
console.log('install 2s')
resolve()
}, 2000)
}))
})
複製代碼
控制檯輸出:
sw state is installing
install 2s
sw state is installed
activate callback
sw state is activating
sw state is activated
複製代碼
self.addEventListener('install',function (event) {
event.waitUntil(new Promise(function(resolve,reject) {
setTimeout(() => {
console.log('install 2s')
reject()
}, 2000)
}))
})
複製代碼
控制檯輸出:
sw state is installing
install 2s
sw state is redundant
Uncaught (in promise) undefined
複製代碼
sw直接進入redundant階段
與install大體都同樣,不一樣的是當你調用reject時,sw不會進入redundant階段,而是最終仍是進入actived階段。
service worker只能捕獲當前目錄及其子目錄下的請求!
好比:
當service worker在/pwa/sw.js下時那麼只能捕獲/pwa/*的請求,因此通常咱們都應該將sw.js放置於/根目錄下。
若是你複製如下代碼將在頁面顯示css代碼
var CACHE_NAME = "gih-cache";
var CACHED_URLS = [
"/pwa/test.css"
];
self.addEventListener('install',function (event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
return cache.addAll(CACHED_URLS);
})
);
})
self.addEventListener('activate',function (event) {
// event.waitUntil(
// caches.keys().then(function(cacheNames) {
// return Promise.all(
// cacheNames.map(function(cacheName) {
// if (CACHE_NAME !== cacheName && cacheName.startsWith("gih-cache")) {
// return caches.delete(cacheName);
// }
// })
// );
// })
// );
})
self.addEventListener('fetch',function (event) {
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
return cache.match(event.request).then(function(response) {
let fetchPromise = fetch(event.request).then(function(networkResponse) {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
return response || fetchPromise;
})
})
);
})
複製代碼
在用戶使用web app時,網頁可能會被關閉,用戶鏈接可能會斷開,甚至服務器有時候也會故障。可是,只要用戶設備上安裝了瀏覽器,後臺同步中的操做就不會消失,直到它成功完成爲止。
在頁面中:
navigator.serviceWorker.ready.then(function(registration) {
registration.sync.register('send-messages');
});
複製代碼
在sw.js中
self.addEventListener("sync", function(event) {
if (event.tag === "send-messages") {
event.waitUntil(function() {
var sent = sendMessages();
if (sent) {
return Promise.resolve();
}else{
return Promise.reject();
}
});
}
});
複製代碼
當後臺屢次嘗試不成功時,那麼sync事件也會提供結束時的標識符event.lastChance。
self.addEventListener("sync", event => {
if (event.tag == "add-reservation") {
event.waitUntil(
addReservation()
.then(function() {
return Promise.resolve();
}).catch(function(error) {
if (event.lastChance) {
return removeReservation();
} else {
return Promise.reject();
}
})
);
}
});
複製代碼
當咱們將邏輯代碼放入service worker中時,咱們就必定會有頁面與service worker通訊的需求,此時postMessage即是這麼一個擔任通訊的角色。
頁面代碼:
navigator.serviceWorker.controller.postMessage( {
arrival: "05/11/2022",
nights: 3,
guests: 2
})
複製代碼
service worker代碼:
self.addEventListener("message", function (event) {
console.log(event.data);
});
複製代碼
頁面代碼:
navigator.serviceWorker.addEventListener("message", function (event) {
console.log(event.data);
});
複製代碼
service worker代碼:
self.clients.matchAll().then(function(clients) {
clients.forEach(function(client) {
if (client.url.includes("/my-account")) {
client.postMessage("Hi client: "+client.id);
}
});
});
複製代碼
service worker代碼:
//當你能夠得到某個客戶端id時即可以向特定的客戶端發送消息
self.clients.get("d2069ced-8f96-4d28").then(function(client) {
client.postMessage("Hi window, you are currently " +
client.visibilityState);
});
複製代碼
//經過clients對象獲取客戶端id
self.clients.matchAll().then(function(clients) {
clients.forEach(function(client) {
self.clients.get(client.id).then(function(client) {
client.postMessage("Messaging using clients.matchAll()");
});
});
});
//經過event.sourse.id 得到·客戶端id
self.addEventListener("message", function(event) {
self.clients.get(event.source.id).then(function(client) {
client.postMessage("Messaging using clients.get(event.source.id)");
});
});
//簡化寫法
self.clients.matchAll().then(function(clients) {
clients.forEach(function(client) {
client.postMessage("Messaging using clients.matchAll()");
});
});
複製代碼
在介紹第四種通訊方式(窗口間通訊)時,我想先插入介紹一下MessageChannel這個對象,他是實現咱們service worker與窗口間相互通訊的一種有效的技術手段。
// 窗口代碼
var msgChan = new MessageChannel();
msgChan.port1.onmessage = function(event) {
console.log("Message received in page:", event.data);
};
var msg = {action: "triple", value: 2};
//這裏能夠是postMessage的第二個參數
navigator.serviceWorker.controller.postMessage(msg, [msgChan.port2]);
// service worker代碼
self.addEventListener("message", function (event) {
var data = event.data;
var openPort = event.ports[0];
if (data.action === "triple") {
openPort.postMessage(data.value*3);
}
});
複製代碼
窗口間通訊方式有多種,你如localStorage這些均可以實現,這裏仍是應該思考如何使用service worker來進行通訊,這裏先再也不贅述。
當咱們的web應用已經使用以上技術作到了一系列的離線優化後,咱們能夠考慮將咱們的應用安裝在本地。
頁面引入:
<link rel="manifest" href="/manifest.json">
複製代碼
manifest.json:
{
"short_name": "Gotham Imperial",
"name": "Gotham Imperial Hotel",
"description": "Book your next stay, manage reservations, and explore Gotham", "start_url": "/my-account?utm_source=pwa",
"scope": "/",
"display": "fullscreen",
"icons": [
{
"src": "/img/app-icon-192.png", "type": "image/png",
"sizes": "192x192"
}, {
}
],
"theme_color": "#242424",
"background_color": "#242424"
}
複製代碼
name與/或short_name:
name 是應用的全名。當空間足夠長時,就會使用這個字段做爲顯示名稱,short_name 能夠做爲短 名的備選方案
start_url:
當用戶點擊圖標時,打開的 URL。能夠是根域名,也能夠是內部頁面。
icon:
包含了一個或多個對象的數組,對象屬性:src(圖標的絕對路徑或者相對路徑)、type(文件類型)和 sizes(圖片的像素尺寸)。要觸發Web應用安裝橫條,清單中至少要包含一個圖標, 尺寸至少是 144像素×144像素。 因爲每一個設備都會根據設備分辨率,從這個數組中選擇最佳的圖標尺寸,所以建議至少 包含 192×192 的圖標和 512×512 的圖標,以覆蓋大多數的設備和用途。
display:
description:
應用的描述。
orientation:
容許你強制指定某個屏幕方向。
theme_color
主題顏色可讓瀏覽器和設備調整 UI 以匹配你的網站(見圖 9-5)。這個顏色的選擇會 影響瀏覽器地址欄顏色、任務切換器中的應用顏色,甚至是設備狀態欄的顏色。主題顏色也能夠經過頁面的meta標籤進行設置(例如:)。若是頁面帶有 theme-color 的 meta 標籤,則該設置會覆蓋清單 中的 theme_color 設置。請注意,雖然 meta 標籤可讓你設置或者覆蓋單個頁面的主 題顏色,可是清單文件中的 theme_color 設置是會影響整個應用的。
background_color
設置應用啓動畫面的顏色以及應用加載時的背景色。一旦加載後,頁面中定義的任何背 景色(經過樣式表或者內聯 HTML 標籤設置)都會覆蓋這一設置;可是,經過將其設 置爲與頁面背景色相同的顏色,就能夠實現從頁面啓動的瞬間到徹底渲染之間的平滑過 渡。若是不設置這一顏色,頁面就會從白色背景啓動,隨後被頁面的背景色替換。
更新中