worker
JavaScript 是一门基于单线程异步操作的语言, 这是为了避免多线程带来的复杂性.
对于一些好事的网络请求, 在 JS 中一般都使用异步执行来避免阻塞.
但是, JS 中也是可以开启其他线程的, 也就是 worker. 可以说这就是 JS 中的多线程.
worker 虽然可以开启主线程以外的线程执行一些其他操作, 但是它和主线程还是有区别的. 应该理解为辅助线程
与主线程的区别
1. 上下文对象不同
通俗讲就是 this 指向不同, 主线程的 this 执行 window 对象(函数内 this 另当别论), 而 worker 线程 this 指向一个 DedicateWorkerGlobalScope 对象. 在 worker 线程中无法使用 window 对象, 在 worker 线程访问 window 会报 window is not defined
异常, 但是仍然可以使用 window 下的许多对象和函数.
2. 无法操作 DOM 元素
在 worker 线程中无法去操作页面的元素, 因为多个线程同时操作 dom 可能导致页面错误, 而且会使程序变得复杂, 所以在 JS 中, 限制了主线程以外的线程操作 dom 元素
创建线程
创建 worker 使用 window 对象的 Worker 构造函数, Worker 接受一个 JS 文件的 URL 作为参数, 该 JS 文件代码将在 worker 线程中执行
main.js
var worker = new Worker('./worker');
worker.js
console.log('worker start');
setInterval(function() {
console.log('worker working');
}, 10000);
终止线程
终止线程可以在 main.js 中调用 worker 对象的 terminate
函数, 也可以在 worker 线程(worker.js)中调用 worker 上下文对象的 close
函数
terminate
main.js
var worker = new Worker('./worker');
// 5秒后终止线程
setTimeout(function() {
worker.terminate();
}, 5000);
worker.js
console.log('worker start');
setInterval(function() {
console.log('worker working');
}, 10000);
close
var worker = new Worker('./worker');
worker.js
console.log('worker start');
setInterval(function() {
console.log('worker working');
}, 1);
// 5秒后终止线程
setTimeout(function( {
close();
}))
线程通信
线程通信时通过 postMessage 函数发送数据, 通过 onmessage 事件监听数据. postMessage 接受一个参数, 这个参数会传递个指定的对应的线程, 对应线程的 onmessage 事件的处理函数接收一个参数 event, event.data 为 postMessage 函数发送的数据. 需要注意的是, 线程间通信的数据是不共享的, 通过 postMessage 发送的数据会被克隆, 生成一个副本. 数据的克隆使用结构化克隆算法(不同浏览器可能实现方式不一样), 所以有些数据无法拷贝, 例如函数. 当传入的数据包含无法克隆的数据类型是, 会抛出一个错误.
main.js
var worker = new Worker('./worker.js');
// 监听 worker.js 中的 postMessage
worker.onmessage = function(event) {
console.log(event.data);
}
// 向 worker 发送一个消息
worker.postMessage('message from main.js');
worker.js
// 接收发送给这个线程的数据
onmessage = function(event) {
console.log(event.data);
// 接收的数据后发送一个 copy 消息
postMessage('message from worker.js');
}
错误处理
当 worker 线程跑出错误时, 会触发 onerror 事件, 可以使用 worker.onerror
事件处理 worker 线程的错误
main.js
var worker = new Worker('./worker');
worker.onerror = function(error) {
console.log('worker throw error: ', error);
}
worker.js
throw new Error('worker throw error');
close();
引入脚本
JS 中用 import
引入其他 JS 代码或其他文件, 在 worker 线程中引入其他 JS 代码使用 importScript
函数. importScript
函数可接收 0 个或多个 JS 文件 URL 作为参数.
worker.js
importScript('./log.js');
log('import script');
log.js
function log(message) {
console.log(message);
}
未完待续…