接下来咱们开始讲解一个使用 Web Worker 运算斐波那契数列的例子。项目地址javascript
首先,咱们须要经过Worker()构造器建立worker实例,其只接受一个参数,该参数则是线程脚本的地址,该地址必须符合同源策略。html
能够查看代码,我再使用同目录下的 dedicate-worker.js 文件建立了一个 Worker 对象出来,当初始化完成后,浏览器后台线程就回运行该脚本了。java
var worker = new Worker('dedicate-worker.js');
复制代码
那主线程(页面)和后台线程的 Worker 之间是如何通讯的呢?这里就要 postMessage 方法了。git
worker.postMessage(message, [transfer]);
复制代码
postMessage 方法接受两个参数,第一个就是 worker 之间传递的数据信息,第二个参数是一个数组,用来转让对象全部权。github
/* html 部分 <div class='normal'> <button onclick='normalPost(34)'>34</button> <button onclick='normalPost(42)'>42</button> </div> */
// js 部分
function normalPost(num) {
worker.postMessage(num);
}
复制代码
上述代码中,当咱们点击对应的按钮时候,会发送数字到对应的到子线程。后台子进程须要监听 onmessage 事件,才能接受主进程发送来的数据。而该事件接受一个 MessageEvent 对象,其中 data 属性就是主进程传入的数据。web
// dedicate-worker.js
// 斐波那契数列
function fabonacci(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fabonacci(n - 1) + fabonacci(n - 2);
}
onmessage = function(messageEvent) {
var str = messageEvent.data;
str = typeof str === 'number' ? String(str) : str;
switch (str) {
// ...
case (str.match(/[0-9]/) || {}).input:
var result = fabonacci(Number(str));
postMessage({msg: str+'的斐波那契数列是:' + result, code: 'fobo'});
break;
default:
postMessage({msg: 'hi, bro~ 慢慢想一下~', code: ''});
break;
}
}
复制代码
上述代码中,咱们经过 onmessage 监听获取主线程传输进来的数据,若是对应的数据运算完成事后,直接调用 postMessage 方法将对应的结果传输出去,注意在子进程的脚本中,由于全局做用域已经改变的缘由是能够直接调用 postMessage 的方法,可是在主进程中是不能够的,是须要指定对应的wroker对象调用的。chrome
回到主进程代码,在这里咱们也只要让对应的 worker 监听 onmessage 事件便可接受由子线程传递过来的数据。数组
worker.addEventListener('message', (e) => {
var res = e.data;
switch (e.data.code) {
default:
app.textContent = res.msg;
break;
}
// ...
});
复制代码
由于 Worker 仍是比较消耗资源的,因此当没有用的时候,能够选择关闭,即调用 terminate 方法便可。浏览器
var worker = new Worker('dedicate-worker.js');
worker.terminate();
复制代码
咱们实现一个多个 tab 共享部分数据效果。大概这样的效果: app
Shared Worker 建立的方法相似于 dedicated Worker,调用 SharedWorker 构造器,语法以下:
new SharedWorker(aURL, name);
复制代码
其中 aURL 表示脚本的地址,name 表示子线程的名字,同名的线程是能够共享的噢,但依旧要遵循同源策略。在咱们的项目中,咱们是这样建立的:
var shareWorker = new SharedWorker('share-worker.js', 'sharedWork');
复制代码
一样的咱们能够经过 postMessage 方法将信息传递给子进程,但由于 SharedWorker 实现的缘由不一样,咱们须要经过实例的 port 属性去调用 postMessage。
input.addEventListener('change', (e) => {
shareWorker.port.postMessage({value: e.target.value, type: 'write'});
})
复制代码
上述代码中,咱们经过监听输入框的 change 事件触发主线程传递信息给子线程。而子线程由于做用域的不一样,对应的链接主线程方式稍有不一样,咱们经过监听 onconnect 接通主线程,而后经过接受参数的 ports 属性获取到 MessagePort
对象,这时候即可以使用 onmessage 和 postMessage 处理和传递数据了。
// ...
onconnect = function (messageEvent) {
messageEvent.source.addEventListener('message', (event) => {
swicthByTypeCode(event.data);
})
source.start();
}
// ...
复制代码
上述代码,主要是子线程链接主线程,并让 MessagePort 对象监听 message 事件,但注意若使用 addEvevntListener 监听的时候,须要自行 start 方法启动。
调试 Dedicated Worker 能够直接在控制台进行调试,惟独调试 SharedWorker 的时候须要进入 chrome://inspect/#workers 点开 inspect 进行调试。
看到了最熟悉的界面,就能够 debugger 调试了。上述仅仅描述了简单的用法,并没有涉及某些高级用法,如 importScripts 的应用、错误处理机制等。其实上文有不断的说起到 Worker 的做用域和 window 的做用域是不一样的,那接下来咱们看看他们究竟是什么样子哩?