一、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的更多相关文章

  1. [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 ...

  2. [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 ...

  3. [PWA] 1. Intro to Service worker

    Service worker stays between our browser and noetwork requests. It can help to fetch data from cache ...

  4. Service Worker和HTTP缓存

    很多人,包括我自己,初看Service Worker多一个Cache Storage的时候,就感觉跟HTTP长缓存没什么区别. 例如大家讲的最多的Service Worker能让网页离线使用,但熟悉H ...

  5. Service Worker

    Service Worker 随着前端快速发展,应用的性能已经变得至关重要,关于这一点大佬做了很多统计.你可以去看看. 如何降低一个页面的网络请求成本从而缩短页面加载资源的时间并降低用户可感知的延时是 ...

  6. Service Worker基础知识整理

    Service Worker是什么 service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本.它的特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),拦截 ...

  7. Service Worker MDN英文笔记

    前言: 以前学习基础知识的时候总看别人写的入门文章,但有时候还是一脸懵逼,直到自己用心阅读了MDN的英文文档才对基础知识的一些理论有了更深的理解,所以我在边阅读文档的时候边记录下帮助比较大的,也方便大 ...

  8. Service Worker 离线无法缓存Post请求的问题解决

    许多非REST API甚至可以用于读取数据的POST请求:典型的例子是graphql.soap和其他rpcpapi.但是,Post请求不能在一个现成的渐进式Web应用程序中缓存和脱机使用.浏览器的缓存 ...

  9. JavaScript是如何工作的:Service Worker的生命周期及使用场景

    摘要: 理解Service Worker. 原文:JavaScript 是如何工作的:Service Worker 的生命周期及使用场景 作者:前端小智 Fundebug经授权转载,版权归原作者所有. ...

随机推荐

  1. sublime的Package Control的安装及使用

    一.快速安装 使用Ctrl+`快捷键或者通过View->Show Console菜单打开命令行,粘贴如下代码(注意下面代码为一行): import urllib.request,os; pf = ...

  2. Linux安装git (git-2.11.0)

      本文旨在讲述如何在linux上安装最新版的git.   1.查看当前git版本:git --version 查看最新版git:访问https://www.kernel.org/pub/softwa ...

  3. 洛谷 P4137 Rmq Problem/mex 题解

    题面 首先,由于本人太菜,不会莫队,所以先采用主席树的做法: 离散化是必须环节,否则动态开点线段数都救不了你: 我们对于每个元素i,插入到1~(i-1)的主席树中,第i颗线段树(权值线段树)对于一个区 ...

  4. django CBV装饰器 自定义django中间件 csrf跨站请求伪造 auth认证模块

    CBV加装饰器 第一种 @method_decorator(装饰器) 加在get上 第二种 @method_decorator(login_auth,name='get') 加在类上 第三种 @met ...

  5. pycharm连接mysql是出现Connection to orm02@127.0.0.1 failed. [08001] Could not create connection to database server. Attempted reconnect 3 times. Giving up.

    下面这个问题反正我是遇到了,也是难为我好几天,于是我决定发一个教程出来给大家看看!希望能帮助你们 原因: 可能是数据库的版本与本机装的驱动不匹配导致的, 解决方案一: 在 url 后面街上一句 因为笔 ...

  6. JavaScript - 过滤敏感字符

    目录 before 源码示例 before 本篇博客展示了如何是在前端对铭感字符及一些特殊的命令做过滤. 好处是,少发一次请求,减少服器校验压力. 源码示例 <!DOCTYPE html> ...

  7. python内置函数0-1

    # a=bool(None)# print(a) class Foo: def __repr__(self): return 'bbbbbbb'f = Foo()ret = ascii(f)print ...

  8. javascript——== 和===的区别

    == 等于 === 全等(值和类型) console.log(5==5);//true console.log(5=="5");//true console.log(5===5); ...

  9. Collections 类和Arrays类常用方法详解

    1:Collections类 max(Collection <? extends T> coll):根据元素的自然顺序,返回给定集合元素中的最大元素 min(Collection < ...

  10. Java基础第四天--常用API

    常用API 基本类型包装类概述 将基本数据类型封装成对象的好处可以在对象中定义更多的功能方法操作该数据 常用的操作之一:用于基本数据类型与字符串之间的转换 基本数据类型 包装类 byte Byte s ...