浅析Service Worker
一、service worker是什么?
平常浏览器窗口中跑的页面运行的是主JavaScript线程,DOM和window全局变量都是可以访问的。
Service Worker是走的另外的线程,可以理解为在浏览器背后默默运行的一个线程,或者说是独立于当前页面的一段运行在浏览器后台进程里的脚本。
它脱离浏览器窗体,异步地运行在一个完全独立的上下文环境,不会对主线程造成阻塞。在service worker中,window以及DOM都是不能访问的,但可以使用self访问全局上下文。
二、service worker的作用?
1.离线缓存(重点)
2.消息推送(重点)
3.后台数据同步
4.响应来自其它源的资源请求,
5.集中接收计算成本高的数据更新,比如地理位置和陀螺仪信息,这样多个页面就可以利6.用同一组数据
7.在客户端进行CoffeeScript,LESS,CJS/AMD等模块编译和依赖管理(用于开发目的)
8.后台服务钩子
9.自定义模板用于特定URL模式
10.性能增强,比如预取用户可能需要的资源,比如相册中的后面数张图片
三、service worker的局限
1、https: Service Worker必须是https协议的,但本地环境下http://localhost或者http://127.0.0.1也可以的。
2、浏览器兼容性:
四、service worker的调试
1、chrome://serviceworker-internals
2、网页中Application
五、service worker的生命周期
Service Worker生命周期的反应: installing → installed → activating → activated
'install'用来缓存文件,'activate'用来缓存更新
六、service worker的用法
1、html中
if ('serviceWorker' in navigator) {
// 开始注册service workers
navigator.serviceWorker.register('./sw-demo-cache.js', {
scope: './'
}).then(function (registration) {
console.log('注册成功');
var serviceWorker;
if (registration.installing) {
serviceWorker = registration.installing;
console.log('安装installing');
} else if (registration.waiting) {
serviceWorker = registration.waiting;
console.log('等待waiting');
} else if (registration.active) {
serviceWorker = registration.active;
console.log('激活active');
}
console.log('=>serviceWorker:', serviceWorker);
if (serviceWorker) {
console.log(serviceWorker.state);
serviceWorker.addEventListener('statechange', function (e) {
console.log(' 状态变化为', e.target.state);
});
// 创建信道
var channel = new MessageChannel();
// port1留给自己
channel.port1.onmessage = e => {
console.log('main thread receive message...');
console.log(e);
}
console.log('给对方', window.RES_MAP);
// port2给对方
serviceWorker.postMessage(window.RES_MAP, [channel.port1]);
serviceWorker.addEventListener('statechange', function (e) {
// logState(e.target.state);
});
}
}).catch(function (error) {
console.log('注册没有成功');
});
} else {
console.log('不支持');
}
2、引进sw-demo-cache.js
// sw
self.addEventListener('message', ev => {
console.log('sw receive message..');
console.log(ev);
fileMap = ev.data.RES_MAP;
var arr1 = [].slice.call(fileMap); // ['a', 'b', 'c']
// 取main thread传来的port2
ev.ports[0].postMessage('Hi, hello too');
});
// var fs = require('fs');
// console.log(fs);
// 缓存
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(VERSION).then(function(cache) {
return cache.addAll([
'./index.html',
]);
})
);
});
// 缓存更新
self.addEventListener('activate', function(event) {
console.log('two now ready to handle fetches!');
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
console.log('cacheName:', cacheName);
// 如果当前版本和缓存版本不一致
if (cacheName !== VERSION) {
return caches.delete(cacheName);
}
})
);
})
);
});
// 捕获请求并返回缓存数据
self.addEventListener('fetch', function (event) {
try{
event.respondWith(
caches.match(event.request).then(function(res){
if(res){
return res;
}
requestBackend(event);
})
)
} catch {
console.log(event);
}
});
function requestBackend(event){
var url = event.request.clone();
return fetch(url).then(function(res){
//if not a valid response send the error
if(!res || res.status !== 200 || res.type !== 'basic'){
return res;
}
var response = res.clone();
console.log('VERSION:', VERSION);
caches.open(VERSION).then(function(cache){
cache.put(event.request, response);
});
return res;
})
}
3、webapck中获取文件目录
引入第三个模块glob,递归获取打包后的文件目录
exports.resMap = function () {
var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
var map = {}
entryFiles.forEach((filePath) => {
var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
map[filename] = filePath;
})
var entryFiles2 = glob.sync(PAGE_PATH2 + '/*')
var map2 = {}
findPath(entryFiles2, map2);
console.log('map2', map2);
return map2;
};
function findPath(entryFiles2, map2) {
entryFiles2.forEach(filePath => {
var filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
if (filePath.indexOf('.') <= 0) {
let pathRes = path.resolve(__dirname, filePath);
let files = glob.sync(pathRes + '/*');
findPath(files, map2);
map2[filename] = filePath;
}
map2[filename] = filePath;
});
}
4、导出目录
通过webpack的DefinePlugin插件,导出上步获取的目录
5、web和service worker的通信
通过postMessage实现web和service worker间的通信
// 创建信道
var channel = new MessageChannel();
// port1留给自己
channel.port1.onmessage = e => {
console.log('main thread receive message...');
console.log(e);
}
console.log('给对方', window.RES_MAP);
// port2给对方
serviceWorker.postMessage(window.RES_MAP, [channel.port1]);
serviceWorker.addEventListener('statechange', function (e) {
// logState(e.target.state);
});
// sw
self.addEventListener('message', ev => {
console.log('sw receive message..');
console.log(ev);
fileMap = ev.data.RES_MAP;
var arr1 = [].slice.call(fileMap); // ['a', 'b', 'c']
// 取main thread传来的port2
ev.ports[0].postMessage('Hi, hello too');
});
小结
1、service worker让离线缓存成为可能,offline情况下也可以访问页面。然而销毁比较困难,更新会有问题。目前只能chrome://serviceworker-internals手动销毁,还待研究。
参考:
借助Service Worker和cacheStorage缓存及离线开发
Service Worker 简介
浅析Service Worker的更多相关文章
- [PWA] 9. Service worker registerion && service work's props, methods and listeners
In some rare cases, you need to ask user to refresh the browsser to update the version. Maybe becaus ...
- [PWA] 2. Service worker life cycle
Once serive worker is registered, the first time we go to the app, we cannot see the logs from servc ...
- [PWA] 1. Intro to Service worker
Service worker stays between our browser and noetwork requests. It can help to fetch data from cache ...
- Service Worker和HTTP缓存
很多人,包括我自己,初看Service Worker多一个Cache Storage的时候,就感觉跟HTTP长缓存没什么区别. 例如大家讲的最多的Service Worker能让网页离线使用,但熟悉H ...
- Service Worker
Service Worker 随着前端快速发展,应用的性能已经变得至关重要,关于这一点大佬做了很多统计.你可以去看看. 如何降低一个页面的网络请求成本从而缩短页面加载资源的时间并降低用户可感知的延时是 ...
- Service Worker基础知识整理
Service Worker是什么 service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本.它的特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),拦截 ...
- Service Worker MDN英文笔记
前言: 以前学习基础知识的时候总看别人写的入门文章,但有时候还是一脸懵逼,直到自己用心阅读了MDN的英文文档才对基础知识的一些理论有了更深的理解,所以我在边阅读文档的时候边记录下帮助比较大的,也方便大 ...
- Service Worker 离线无法缓存Post请求的问题解决
许多非REST API甚至可以用于读取数据的POST请求:典型的例子是graphql.soap和其他rpcpapi.但是,Post请求不能在一个现成的渐进式Web应用程序中缓存和脱机使用.浏览器的缓存 ...
- JavaScript是如何工作的:Service Worker的生命周期及使用场景
摘要: 理解Service Worker. 原文:JavaScript 是如何工作的:Service Worker 的生命周期及使用场景 作者:前端小智 Fundebug经授权转载,版权归原作者所有. ...
随机推荐
- ES6中Set和Map
1.Set 实例的创建 Set实例它类似于数组,但是成员的值都是唯一的,没有重复的值. Set本身是一个构造函数用来生成Set数据结构. Set 函数可以接受一个数组(或者具有 iterable 接口 ...
- AirFlow功能展示个人笔记
DAGs 查看您可以一目了然地查看成功.失败及当前正在运行的任务数量. 选中其中一个DAG 树视图 跨越时间的 DAG 的树表示.如果 pipeline(管道)延迟了,您可以很快地看到哪里出现了错误的 ...
- ######<待随时补充>我的学习规划######
一.关于Python 1.demo 一些基础实验,包含Python基础知识等,约300-500个 2.Python常见模块的了解学习,如 time datetime random 随机数 os 与 ...
- hard or 9102 字符串DP---Educational Codeforces Round 57 (Rated for Div. 2)
题意:http://codeforces.com/problemset/problem/1096/D 思路:参考:https://blog.csdn.net/qq_41289920/article/d ...
- 状压DP--Rotate Columns (hard version)-- Codeforces Round #584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2)
题意:https://codeforc.es/problemset/problem/1209/E2 给你一个n(1-12)行m(1-2000)列的矩阵,每一列都可以上下循环移动(类似密码锁). 问你移 ...
- 经验:什么影响了数据库查询速度、什么影响了MySQL性能 (转)
一.什么影响了数据库查询速度 1.1 影响数据库查询速度的四个因素 1.2 风险分析 QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定 ...
- T100——动态更改Label的说明
例子: #設定科目名稱 IF g_prog = 'aapt300' THEN CALL cl_set_comp_att_text("lbl_apca036",cl ...
- Dom编程-左侧菜单栏设计模型实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 18-Perl 错误处理
1.Perl 错误处理程序运行过程中,总会碰到各式各样的错误,比如打开一个不存在的文件.程序运行过程中如果出现错误就会停止,我们就需要使用一些检测方法来避免错误,从而防止程序退出.Perl 提供了多中 ...
- Js 更换html同一父元素下子元素的位置
//更换两个元素的位置 var exchange=function (el1, el2) { var ep1 = el1[0].parentNode, ep2 = el2[0].parentNode, ...