首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >咱们worker有力量-在浏览器中实现多线程和离线应用

咱们worker有力量-在浏览器中实现多线程和离线应用

作者头像
江米小枣
发布2020-06-16 16:56:13
2.4K0
发布2020-06-16 16:56:13
举报
文章被收录于专栏:云前端云前端

今天真正要说的是 -- JavaScript 中的 worker 们

在 HTML5 规范中提出了工作线程(Web Worker)的概念,允许开发人员编写能够脱离主线程、长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。

Web Worker 又分为 Dedicated WorkerSharedWorker

随后 ServiceWorker 也加入进来,用于更好的控制缓存和处理请求,让离线应用成为可能。

I. 进程和线程

先来复习一下基础知识:

  • 进程(process)和线程(thread)是操作系统(OS) 里面的两个基本概念
  • 对于 OS 来说,一个任务就是一个进程;比如 Chrome 浏览器每打开一个窗口就新建一个进程
  • 一个进程可以由多个线程组成,它们分别执行不同的任务;比如 Word 可以借助不同线程同时进行打字、拼写检查、打印等
  • 区别在于:每个进程都需要 OS 为其分配独立的内存地址空间,而同一进程中的所有线程共享同一块地址空间
  • 多线程可以并发(时间上快速交替)执行,或在多核 CPU 上并行执行

传统页面中(HTML5 之前)的 JavaScript 的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:JavaScript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。

为了避免多线程 UI 操作的冲突(如线程1要求浏览器删除DOM节点,线程2却希望修改这个节点的某些样式风格),JS 将处理用户交互、定时执行、操作DOM树/CSS样式树等,都放在了 JS 引擎的一个线程中执行。

从 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能。它不但强化了 Web 系统或网页的表现性能,而且还增加了对本地数据库等 Web 应用功能的支持。

随之而来的,还有上面提到的几种 worker,首先解决的就是多线程的问题。

II. Master-Worker 模式

那么,来看看解决线程问题的东西为什么叫 worker,这来源于一种设计模式:

Master-Worker模式是常用的并行设计模式。其核心思想是:系统有两个进程协同工作:Master进程和Worker进程。Master进程负责接收和分配任务,Worker进程负责处理子任务。当各个Worker进程将子任务处理完后,将结果返回给Master进程,由Master进行归纳和汇总,从而得到系统结果

实例:Node.js 中的 Master-Worker 模式

Node 的内置模块 cluster,可以通过一个主进程管理若干子进程的方式来实现集群的功能

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;if (cluster.isMaster) { //主进程 console.log(`Master ${process.pid} is running`); //分配子任务
 for (let i = 0; i < numCPUs; i++) {
   cluster.fork();
 }
 
} else { //子进程 //应用逻辑根本不需要知道自己是在集群还是单边
 //每个HTTP server都能监听到同一个端口
 http.createServer((req, res) => {
   res.writeHead(200);
   res.end('hello world\n');
 }).listen(8000); console.log(`Worker ${process.pid} started`);
 
}

运行 node server.js 后,输出:

Master 3596 is running
Worker 4324 started
Worker 4520 started
Worker 6056 started
Worker 5644 started

III. Web Worker

在 HTML5 中,Web Worker 的出现使得在 Web 页面中进行多线程编程成为可能

HTML5 中的多线程是这样一种机制:它允许在 Web 程序中并发执行多个 JavaScript 脚本,每个脚本执行流都称为一个线程,彼此间上下文互相独立,并且由浏览器中的 JavaScript 引擎负责管理

HTML5 规范列出了 Web Worker 的三大主要特征:

  • 能够长时间运行(响应)
  • 理想的启动性能
  • 理想的内存消耗

HTML5 中的 Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker

(3.1) 专用线程 Dedicated Worker

专用线程是指标准 worker,一个专用 worker 仅仅能被生成它的脚本所使用

也就是说,所谓的专用线程(dedicated worker)并没有一个显示的DedicatedWorker构造函数,其实指的就是普通的Worker构造函数。

? 在解释概念前,先来看一个呗儿简单的小栗子:

//myWorker.jsself.onmessage = function(event) {
   var info = event.data;
   self.postMessage(info + " from worker!");
};
//主页面<input type="text" name="wkInput1" />
<button id="btn1">test!</button><script>
if (window.Worker) {
   const myWorker = new Worker("myWorker.js");
   myWorker.onmessage = function (event) {
       alert(event.data);
   };
   
   const btn = document.querySelector('#btn1');
   btn.addEventListener('click', e=>{
       const ipt = document.querySelector('[name=wkInput1]');
       const info = "hello " + ipt.value;
       myWorker.postMessage(info);
   });
}
</script>

很显然,运行的效果无非是点击按钮后弹出包含文本框内容的字符串。

例子很简单,但携带的关键信息还算丰富,那么结合规范中的一些定义来看一看上面的代码:

首先是专用 worker 在运行的过程中,会隐式的使用一个MessagePort对象,其接口定义如下:

interface MessagePort {
 void postMessage(message, optional transfer = []);
 attribute onmessage;
 
 void start();
 void close();
 attribute onmessageerror;
};

我们把最重要的两个成员放在了前面,一个是postMessage()方法,另一个是onmessage属性。

  • postMessage()方法用来发送数据:第一个参数除了可以发送字符串,还可以发送 JS 对象(有的浏览器需要JSON.stringify());可选的第二个参数可用来发送 ArrayBuffer 对象数据(一种二进制数组,配合XHR、File API、Canvas等读取字节流数据用)
  • onmessage属性应被指定一个事件处理函数,用于接收传递过来的消息;也可以选择使用 addEventListener 方法,其实现方式和作用和 onmessage 相同

然后来看看简化后的 Worker 的定义:

interface AbstractWorker {
 attribute onerror;
};
interface Worker {
 Constructor(scriptURL, optional workerOptions);
 
 void terminate(); void postMessage(message, optional transfer = []);
 attribute onmessage;
 attribute onmessageerror;
};Worker implements AbstractWorker;
  • 首先它实现了AbstractWorker接口,也就是说有一个onerror回调用来管理错误;
myWorker.onerror = function(event){
   console.log(event.message);
   console.log(event.filename);
   console.log(event.lineno);
}
  • 其次,明显也实现了上面提到过的MessagePort接口,可以 postMessage/onmessage
  • 实例化一个新的 worker 只需要调用 Worker() 的构造方法,指定一个脚本的 URI
  • 当创建完 worker 以后,可以调用 terminate() 方法去终止该线程

通过workerOptions 中的选项可以支持 es6 模块化等,这里不展开论述

至此,已经可以理解“主页面”中的各种定义和调用行为了;而"myWorker.js"中的self又是怎样的呢,继续来看看相关定义:

interface WorkerGlobalScope {
 readonly attribute self; //WorkerGlobalScope
 readonly attribute location;
 readonly attribute navigator;
 void importScripts(urls); attribute onerror;
 attribute onlanguagechange;
 attribute onoffline;
 attribute ononline;
 attribute onrejectionhandled;
 attribute onunhandledrejection;
};
interface DedicatedWorkerGlobalScope {
 readonly attribute name; void postMessage(
   message,
   optional transfer = []
 ); void close(); attribute onmessage;
 attribute onmessageerror;
};

专用 worker 实现了以上两个接口,可知:

  • worker中的全局对象就是其本身
  • 可以使用 WorkerGlobalScopeself 只读属性来获得这个对象本身的引用
  • 并且可以调用相关的MessagePort接口方法。

看起来很简单,两边都可以 postMessage/onmessage,就可以愉快的通信了。

除了上述这些,其他的一些要点包括:

  • 为了安全,在 worker 中不能访问 DOM
  • 作为参数传递给 worker 构造器的 URI 必须遵循同源策略
  • worker 不能访问 window 对象,也不能调用 alert()
  • 可以在只读的 navigator 对象中访问 appName、appVersion、platform、onLine 和 userAgent 等
  • 可以在只读的 location 对象中获取 hostname 和 port 等
  • 在 worker 中也支持 XMLHttpRequest 和 fetch 等
  • 支持 importScripts() 方法(在同一个域上异步引入脚本文件),该函数接受0个或者多个URI作为参数
  • 支持 JavaScript 对象,比如 Object、Array、Date、Math 和 String
  • 支持 setTimeout() 和 setInterval() 方法
  • 在主线程中使用时,onmessage 和 postMessage() 必须挂在worker对象上,而在worker中使用时不用这样做。原因是,在worker内部,worker是有效的全局作用域
专用 worker 相对理想的兼容情况

在现代浏览器和移动端上,可以说专用 worker 已经被支持的不错了:

(3.2) 共享线程 Shared Worker

共享线程指的是一个可以被多个页面通过多个连接所使用的 worker

? 还是先看一个栗子:

//wk.jsvar arr = [];self.onconnect = function(e) {
   var port = e.ports[0];
   port.postMessage('hello from worker!');   port.onmessage = function(evt) {
       var val = evt.data;
       if (!~arr.indexOf(val)) {
           arr.push(val);
       }
       port.postMessage(arr.toString());
   }
}
<!DOCTYPE html>
<html><body>
page 1
<script>
if (window.SharedWorker) {
   var wk = new SharedWorker('wk.js');
   wk.port.onmessage = function(e) {
       console.log(e.data);
   }
   wk.port.postMessage(1);
}//输出
//hello from worker!
//1
</script>
</body></html>
<!DOCTYPE html>
<html><body>
page 2
<script>
if (window.SharedWorker) {
   var wk = new SharedWorker('wk.js');
   wk.port.onmessage = function(e) {
       console.log(e.data);
   }
   wk.port.postMessage(2);
}
   
//输出
//hello from worker!
//1,2
</script>
</body></html>

运行效果也不难理解,引用共享 worker 的两个同域的页面,共享了其中的 arr 数组。也就是说,专用 worker 一旦被某个页面引用,该页面就拥有了一个独立的子线程上下文;与之不同的是,某个共享 worker 脚本文件如果被若干页面(要求是同源的)引用,则这些页面会共享该 worker 的上下文,拥有共同影响的变量等。

interface SharedWorker {
 Constructor(
   scriptURL,
   optional (DOMString or WorkerOptions) options
 );
 
 readonly attribute port;
};SharedWorker implements AbstractWorker;

另一个非常大的区别在于,前面也提到过,与一个专用 worker 通信,对MessagePort的实现是隐式进行的(直接在 worker 上进行postMessage/onmessage);而共享 worker 必须通过端口(MessagePort类型的worker.port)对象进行。

此外的几个注意点:

var wk = new SharedWorker('wk.js', 'foo');
//or
var wk = new SharedWorker('wk.js', {name: 'foo'});
interface SharedWorkerGlobalScope {
 readonly attribute name;
 void close();
 attribute onconnect;
};
  • 实例化时添加的第二个参数,用于指定这个共享 worker 的名称,必须要同名才能共享;这个 name 在 worker 中可以藉由 self.name 获得
self.onconnect = function(e) {
   var port = e.ports[0];
   port.postMessage('hello from worker!');
   //...
}
  • 在共享 worker 的 onconnect 回调中直接发送了一个 postMessage,用于提示连接成功,这个动作在页面刷新后并不会重新执行,而是重新打开页面才会执行。
var wk = new SharedWorker('wk.js');
wk.port.onmessage = function(e) {
   console.log(e.data);
}//-->
wk.port.addEventListener('message', function(e) {
   console.log(e.data);
});
wk.port.start();
  • 如果用addEventListener代替onmessge,则需要额外调用 start() 方法才能建立连接
共享大法虽好,兼容仍需谨慎

移动端尚不支持、IE11/Edge也没戏;测试时 Mac 端的 chrome/firefox 也是状况频频无法成功,最后在 chrome@win10 以及 opera@mac 才可以

IV. Service Worker

Service Worker 基于 Web Worker 的事件驱动,提供了用来管理安装、版本、升级的一整套系统。

专用 worker 或共享 worker 专注于解决 “耗时的 JS 执行影响 UI 响应” 的问题, -- 一是后台运行 JS,不影响主线程;二是使用postMessage()/onmessage消息机制实现了并行。

而 service worker 则是为解决 “因为依赖并容易丢失网络连接,从而造成 Web App 的用户体验不如 Native App” 的问题而提供的一系列技术集合;它比 web worker 独立得更彻底,可以在页面没有打开的时候就运行。

并且相比于已经被废弃的 Application Cache 缓存技术:

<html manifest="appcache.manifest">
 ...
</html>
CACHE MANIFEST
# appcache.manifest text file, version: 0.517NETWORK:
#CACHE:
assets/loading.gif
assets/wei_shop_bk1.jpg
assets/wei_shop_bk2.jpg
assets/wei_ios/icons.png
assets/wei_ios/icon_addr.png
assets/wei_ios/icon_tel.pngNETWORK:
scripts/wei_webapp.js
styles/meishi_wei.css

service worker 拥有更精细、更完整的控制;作为一个页面与服务器之间代理中间层,service worker 可以捕获它所负责的页面的请求,并返回相应资源,这使离线 web 应用成为了可能。

? 一如既往的先看一个直观的小栗子:

<!--http://localhost:8000/service.html--><h1>hello service!</h1><img src="deer.png" /><script>
if (navigator.serviceWorker) {
   window.onload = function() {
       navigator.serviceWorker.register(
           'myService.js',
           {scope: '/'}
       ).then(registration=>{
           console.log('SW register OK with scope: ', registration.scope);           registration.onmessage = function(e) {
               console.log(e.data)
           }
       }).catch(err=>{
           console.log('SW register failed: ', err);
       });
   }
   
   // SW register OK with scope:  http://localhost:8000/
}
</script>
//myService.jsvar CACHE_NAME = 'my-site-cache-v1';var urlsToCache = [
 '/styles/main.css',
 '/script/main.js'
];self.addEventListener('install', function(event) {
 event.waitUntil(
   caches.open(CACHE_NAME)
     .then(function(cache) {
       return cache.addAll(urlsToCache);
     })
 );
});self.addEventListener('fetch', function(event) {
 const url = new URL(event.request.url);
 if (url.pathname == '/deer.png') {
   event.respondWith(
     fetch('/horse.jpg').catch(ex=>console.log(ex))
   );
 } else {
   event.respondWith(
     caches.match(event.request)
       .then(function(response) {
         if (response) {
           return response;
         }
         return fetch(event.request);
       }
     )
   );
 }
});

结合这个简单的示例,来梳理一下其中反映出的信息:

(4.1) 基础组成元素

Promise

和其他两种 worker 不同的是,service worker 中的各项技术广泛地利用了 Promise

Promises 是一种非常适用于异步操作的机制,一个操作依赖于另一个操作的成功执行。这也成为了 service worker 的通用工作机制

Response 对象

Response 的构造函数允许创建一个自定义的响应对象:

new Response('<p>Hello from service worker!</p>', {
 headers: { 'Content-Type': 'text/html' }
})

但更常见的是:通过其他的 API 操作返回了一个 Response 对象,例如一个 service worker 的 event.respondWith ,或者一个简单的 fetch()

在 service worker 中使用 Response 对象时,通常还要通过 response.clone() 来取得一个克隆使用;这样做的原因是,一个 response 是一个流,只用被消费一次,而我们想让浏览器、缓存等多次操作这个响应,就需要 clone 出不同的对象来;对于 Request 请求对象的使用也是类似的道理

Fetch

在 service worker 中无法使用传统的 XMLHttpRequest,只能使用 fetch;而后者的优势正在于,可以使用 RequestResponse 对象

每次网络请求,都会触发对应的 service worker 中的 fetch 事件

在我们的例子中,页面上有一个指向 deer.png 的图片元素,最后却由 fetch 事件回调拦截并返回了 /horse.jpg,实现了指鹿为马的自定义资源指向

self.addEventListener('fetch', function(event) {
 const url = new URL(event.request.url);
 if (url.pathname == '/deer.png') {
   event.respondWith(
     fetch('/horse.jpg').catch(ex=>console.log(ex))
   );
 }
});
Catch

在 service worker 规范中包含了原生的缓存能力,用以替代已被废弃的 Application Cache 标准。

Cache API 提供了一个网络请求的持久层,并可以使用 match 操作查询这些请求。

在 service worker 中最主要用到 Cache 的地方,还是在上面提到的 fetch 事件回调中。

通过使用本地缓存中的资源,不但能省去对网络的昂贵访问,更有了在 离线、掉线、网络不佳 等情况下维持应用可用的能力。

相关的定义如下:

interface Cache {
 match(request, optional cacheQueryOptions);
 matchAll(optional request, optional cacheQueryOptions);
 add(request);
 addAll(requests);
 put(request, response);
 delete(request, optional cacheQueryOptions);
 keys(optional request, optional cacheQueryOptions);
};

同时 service worker 也可以用 self.caches 来取得缓存:

interface WindowOrWorkerGlobalScope {
 readonly attribute caches; //CacheStorage
};interface CacheStorage {
 match(request, optional options); //Promise
 has(cacheName); //Promise
 open(cacheName); //Promise
 delete(cacheName); //Promise
 keys(); //Promise
};

反映在例子中就是(版本的部分会在稍后提到):

self.addEventListener('install', function(event) {
 event.waitUntil(
   caches.open(CACHE_NAME)
     .then(function(cache) {
       return cache.addAll(urlsToCache);
     })
 );
});self.addEventListener('fetch', function(event) {
   event.respondWith(
     caches.match(event.request)
       .then(function(response) {
         if (response) {
           return response;
         }
         return fetch(event.request);
       }
     )
   );
});

(4.2) 生命周期

完整的生命周期

将 server worker 的生命周期设计成这样,其目的在于:

  • 实现离线优先
  • 允许新服务工作线程自行做好运行准备,无需中断当前的服务工作线程
  • 确保整个过程中作用域页面由同一个服务工作线程(或者没有服务工作线程)控制
  • 确保每次只运行网站的一个版本
对应的事件

重要的比如:

  • install事件:使用register() 注册时会触发
  • activate事件:register() 注册时也会触发activate事件

具体到各个事件的回调中,event 参数对应的类型如下:

事件名称

接口

install

ExtendableEvent

activate

ExtendableEvent

fetch

FetchEvent

message

ExtendableMessageEvent

messageerror

MessageEvent

其中有代表性的两个事件的定义如下:

interface ExtendableEvent {
 void waitUntil(promiseFunc);
};interface FetchEvent {
 readonly attribute request;
 readonly attribute clientId;
 readonly attribute reservedClientId;
 readonly attribute targetClientId; void respondWith(promiseFunc);
};

所以,才可以在例子中调用 event.waitUntil()event.respondWith()

self.addEventListener('install', function(event) {
 event.waitUntil( //用一个 promise 检查安装是否成功
   //...
 );
});self.addEventListener('fetch', function(event) {
 event.respondWith( // 返回符合期望的 Response 对象
   //...
 );
注册

不同于其他两种 worker 的是,service worker 不再用 new 来实例化,而是直接通过 navigator.serviceWorker 取得

navigator.serviceWorker 实际上实现了 ServiceWorkerContainer 接口:

interface ServiceWorkerContainer {
 readonly attribute controller;
 readonly attribute ready; //promise register(scriptURL, optional registrationOptions); getRegistration(optional clientURL = "");
 
 getRegistrations(); void startMessages(); attribute oncontrollerchange;
 attribute onmessage; // event.source is a worker
 attribute onmessageerror;
};

比如我们在例子中的主页面所做的:

navigator.serviceWorker.register(
   'myService.js',
   {scope: '/'}
).then().catch()

scope 参数是选填的,可以被用来指定想让 service worker 控制的内容的子目录;service worker 能控制的最大权限层级就是其所在的目录

运行 register() 方法成功的话,会在 navigator.serviceWorker 的 Promise 的 then 回调中得到一个 ServiceWorkerRegistration 类型的对象;

正如例子中所示,主页面中就可以用这个实例化后的 'registration' 对象调用 onmessage

interface ServiceWorkerRegistration {
 readonly attribute installing;
 readonly attribute waiting;
 readonly attribute active;
 
 readonly attribute scope;
 
 readonly attribute updateViaCache; update(); //in promise
 unregister(); //in promise attribute onupdatefound;
};

同时如果 register() 成功,service worker 就在 ServiceWorkerGlobalScope 环境中运行;

也就是说,myService.js 中引用的 self 就是这个类型了,可以调用 self.skipWaiting() 等方法;

这是一个特殊类型的 worker 上下文运行环境,与主运行线程相独立,同时也没有访问 DOM 等能力

interface ServiceWorkerGlobalScope {
 readonly attribute clients;
 readonly attribute registration; skipWaiting(); attribute oninstall;
 attribute onactivate;
 attribute onfetch; attribute onmessage; // event.source is a client
 attribute onmessageerror;
};

和 shared worker 类似,需要小心 service worker 脚本里的全局变量: 每个页面不会有自己独有的worker

安装

在 service worker 注册之后,install 事件会被触发

在 install 回调中,一般执行以下任务:

  • 打开制定版本的缓存
  • 缓存文件
  • 确认所有需要的资源是否被缓存
  • 如有指定的任何缓存文件无法下载,则安装步骤将失败
更新
  • 更新 service worker 所在的 JavaScript 文件。用户打开页面时,浏览器会尝试在后台重新下载该 JS 文件;如果该文件与其当前所用文件存在字节差异,则将其视为“新版本的 service worker”。
  • 新服务工作线程将会启动,且将会触发 install 事件
  • 如果 service worker 已经被安装,但是刷新页面时有一个新版本的可用 -- 那么新版本虽会在后台安装,但还不会激活,且进入 waiting 状态
  • 当不再有任何已加载的页面在使用旧版的 service worker 的时候,新版本才会激活,并触发其 activate 事件

出现在 activate 回调中的一个常见任务是缓存管理。在这个步骤进行缓存管理,而不是在之前的安装阶段进行,原因在于:如果在 install 步骤中清除了任何旧缓存,则继续控制所有当前页面的任何旧 service worker 将突然无法从缓存中提供文件

self.addEventListener('activate', function(event) { var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1']; event.waitUntil(
   caches.keys().then(function(cacheNames) {
     return Promise.all(
       cacheNames.map(function(cacheName) {
         if (cacheWhitelist.indexOf(cacheName) === -1) {
           return caches.delete(cacheName);
         }
       })
     );
   })
 );
});

(4.3) 其他

需要 HTTPS
  1. 出于安全考虑,目前只能在 HTTPS 环境下才能使用 service worker;不符合则会抛出错误 DOMException: Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).
  2. 在测试时,是可以用 http://localhost 进行的
后台同步

后台同步(Background Sync)是基于 service worker 构建的另一个功能。允许用户一次性或按间隔时间请求后台数据同步。

  • 即使用户没有为您的网站打开标签,也会如此,仅唤醒 service worker
  • 从页面请求执行此操作的权限,用户将收到提示
  • 适用于非紧急更新,如社交时间表或新闻文章
navigator.serviceWorker.register('sw.js');//...navigator.serviceWorker.ready.then(registration=>{
 registration.sync.register('update-leaderboard').then(function() {
   // registration succeeded
 }, function() {
   // registration failed
 });
});
//sw.js
self.addEventListener('sync', function(event) {
 if (event.id == 'update-leaderboard') {
   event.waitUntil(
     caches.open('mygame-dynamic').then(function(cache) {
       return cache.add('/leaderboard.json');
     })
   );
 }
});
推送

Push API 是基于 service worker 构建的另一个功能。该 API 允许唤醒 service worker 以响应来自操作系统消息传递服务的消息。

  • 即使用户没有为您的网站打开标签,也会如此,仅唤醒 service worker
  • 从页面请求执行此操作的权限,用户将收到提示
  • 适合于与通知相关的内容,如聊天消息、突发新闻或电子邮件
  • 同时可用于频繁更改受益于立即同步的内容,如待办事项更新或日历更改
  • 需要 google 的 FCM 通道服务,目前国内无法使用
chrome 离线小恐龙的游戏

正是基于 service worker,chrome 在网络不可用时会显示小恐龙冒险的离线游戏,按下空格键,就可以开始了~

(4.4) Service Worker 的浏览器兼容性

由于一些相关的 google 服务无法用,iOS 上对其的支持也有限并在试验阶段,所以尚不具备大规模应用的条件;

但作为渐进式网络应用技术 PWA 中的最重要的组成部分,国内很多厂商已经在尝试推进相关的支持,未来值得期待:

V. 总结

  • Master-Worker 是常用的并行设计模式,用worker表示线程相关的概念就来源于此
  • web worker 的出现使得在 Web 页面中进行多线程编程成为可能
  • 共享线程指的是一个可以被多个页面通过多个连接所使用的 worker,页面会共享 worker 的上下文,拥有共同影响的变量等
  • service worker 作为一个页面与服务器之间的 proxy,可以捕获它所负责的页面的请求,并返回相应资源,这使离线 web 应用成为了可能
  • 兼容性方面,专用 worker 相对理想一些,共享 worker 不太理想,service worker 值得期待

VI. 参考资料:

  • https://superuser.com/questions/257406/can-a-multi-core-processor-run-multiple-processes-at-the-same-time
  • http://www.cnblogs.com/whitewolf/p/javascript-single-thread-and-browser-event-loop.html
  • http://woshixiguapi.blog.163.com/blog/static/19249969201010113479457/
  • http://www.cnblogs.com/Leo_wl/p/5319735.html
  • http://www.alloyteam.com/2015/08/nodejs-cluster-tutorial/
  • https://php.golaravel.com/function.pcntl-fork.html
  • https://developer.mozilla.org/zh-CN/docs/Web/API/WebWorkersAPI/Usingwebworkers
  • https://developer.mozilla.org/zh-CN/docs/Web/API/ServiceWorkerAPI/UsingServiceWorkers
  • https://www.smashingmagazine.com/2016/02/making-a-service-worker/
  • https://developer.mozilla.org/zh-CN/docs/Web/API/ServiceWorkerAPI
  • http://blog.88mph.io/2017/07/28/understanding-service-workers/
  • https://serviceworke.rs/
  • https://aarontgrogg.com/blog/2015/07/20/the-difference-between-service-workers-web-workers-and-websockets/
  • https://www.fxsitecompat.com/en-CA/docs/2015/application-cache-api-has-been-deprecated/
  • https://24ways.org/2016/http2-server-push-and-service-workers/
  • https://ponyfoo.com/articles/backgroundsync
  • https://www.ibm.com/developerworks/cn/web/1112sunchwebworker/
  • https://www.ibm.com/developerworks/cn/web/wa-webworkers/index.html
  • https://www.quora.com/Whats-the-difference-between-service-workers-and-web-workers-in-JavaScript
  • http://jixianqianduan.com/frontend-javascript/2014/06/05/webworker-serviceworker.html
  • https://zhuanlan.zhihu.com/p/27264234
  • https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/
  • http://imweb.io/topic/56592b8a823633e31839fc01
  • https://w3c.github.io/ServiceWorker/#service-worker-concept
  • http://www.howtobuildsoftware.com/index.php/how-do/97C/service-worker-what-is-the-api-for-unregistering-service-workers-in-chrome-44
  • https://developers.google.com/web/fundamentals/primers/service-workers/
  • https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/
  • https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#_2
  • https://juejin.im/post/59d9b38ef265da064a0f72cc
  • https://nolanlawson.github.io/cascadia-2016/#/37
  • https://love2dev.com/blog/what-is-a-service-worker/

(end)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • I. 进程和线程
  • II. Master-Worker 模式
    • 实例:Node.js 中的 Master-Worker 模式
    • III. Web Worker
      • (3.1) 专用线程 Dedicated Worker
        • 专用 worker 相对理想的兼容情况
      • (3.2) 共享线程 Shared Worker
        • 共享大法虽好,兼容仍需谨慎
    • IV. Service Worker
      • (4.1) 基础组成元素
        • Promise
        • Response 对象
        • Fetch
        • Catch
      • (4.2) 生命周期
        • 完整的生命周期
        • 对应的事件
        • 注册
        • 安装
        • 更新
      • (4.3) 其他
        • 需要 HTTPS
        • 后台同步
        • 推送
        • chrome 离线小恐龙的游戏
      • (4.4) Service Worker 的浏览器兼容性
      • V. 总结
      • VI. 参考资料:
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档