我将带你快速熟悉一个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 标签设置)都会覆盖这一设置;可是,经过将其设 置为与页面背景色相同的颜色,就能够实现从页面启动的瞬间到彻底渲染之间的平滑过 渡。若是不设置这一颜色,页面就会从白色背景启动,随后被页面的背景色替换。
更新中