跳到主要内容

工作者线程概览与专用线程

工作者线程有哪些特性与类型?​

  • 特性: 基于线程实现, 与主线程并行运行, 可共享部分内存, 不保证在同一进程内;
  • 专用工作者线程: 由单个页面独占;
  • 共享工作者线程: 可被多个同源上下文使用;
  • 服务工作者线程: 用于拦截、重定向与修改 HTTP 请求;

工作者线程中的全局对象是什么?​

  • 对象: WorkerGlobalScope, 只暴露部分浏览器 API;
属性方法
navigatorsetTimeout / clearTimeout
selfsetInterval / clearInterval
locationfetch
consoleatob / btoa
caches / indexedDBcreateImageBitmap
isSecureContext/origin
  • 限制:
    • DOM: 无法访问 document、window、parent 等主线程 DOM 对象;
    • 全局对象: 只定义 Navigator 与 Location;
    • 脚本: 无法使用 alert() 与 confirm();

专用工作者线程提供哪些 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() 按加载顺序同步执行;
  • 作用域: 导入的脚本共享工作者线程作用域, 且可加载任意源的脚本;