工作者线程概览与专用线程
工作者线程有哪些特性与类型?
- 特性: 基于线程实现, 与主线程并行运行, 可共享部分内存, 不保证在同一进程内;
- 专用工作者线程: 由单个页面独占;
- 共享工作者线程: 可被多个同源上下文使用;
- 服务工作者线程: 用于拦截、重定向与修改 HTTP 请求;
工作者线程中的全局对象是什么?
- 对象:
WorkerGlobalScope, 只暴露部分浏览器 API;
| 属性 | 方法 |
|---|---|
navigator | setTimeout / clearTimeout |
self | setInterval / clearInterval |
location | fetch |
console | atob / btoa |
caches / indexedDB | createImageBitmap |
isSecureContext/origin |
- 限制:
- DOM: 无法访问
document、window、parent等主线程 DOM 对象; - 全局对象: 只定义
Navigator与Location; - 脚本: 无法使用
alert()与confirm();
- DOM: 无法访问
专用工作者线程提供哪些 API?
| 成员 | 作用 |
|---|---|
new Worker(scriptURL, options?) | 创建专用工作者线程 |
worker.postMessage(message, transfer?) | 向线程发送消息 |
worker.terminate() | 立即终止线程 |
worker.onmessage / onerror / onmessageerror | 接收消息 / 错误 / 序列化失败 |
self.name | 线程标识符 |
self.postMessage(message, transfer?) | 向主线程发送消息 |
self.close() | 请求关闭线程 |
self.importScripts(...urls) | 按顺序同步导入外部脚本 |
const sameOriginWorker = new Worker("./worker.js");
close 与 terminate 有什么区别?
close(): 通知线程取消下一个事件循环, 当前事件循环内的任务仍会执行完;terminate(): 立即终止线程, 强制中断当前事件循环, 之后的postMessage不会执行;
// close: 当前循环内的任务仍执行
self.postMessage("foo");
self.close();
self.postMessage("bar"); // 仍执行
setTimeout(() => self.postMessage("baz"), 0); // 被取消
同源、回收与错误如何处理?
- 同源策略: 只能加载同源脚本;
- 垃圾回收: 未调用
close()或terminate()时线程不会被回收, 即使脚本已执行完; - 错误隔离: 线程出错不会打断主线程, 主线程通过
error事件感知;
const worker = new Worker("./worker.js");
worker.onerror = console.log; // 线程内 throw Error("foo") 时触发
如何动态创建线程与导入脚本?
- 行内创建: 用
Blob包住脚本内容, 再用URL.createObjectURL得到地址;
const workerScript = `self.onmessage = ({ data }) => console.log(data);`;
const url = URL.createObjectURL(new Blob([workerScript]));
const worker = new Worker(url);
- 动态导入: 用
importScripts()按加载顺序同步执行; - 作用域: 导入的脚本共享工作者线程作用域, 且可加载任意源的脚本;