前言

在上一篇 << 单线程 与 执行机制 >> 中, 我们提到了 Web Worker.

它的诞生是为了解决 JS 主线程执行耗时计算时, 导致 UI 无法及时更新的卡死现象.

它的解决思路是把同步代码异步化. 原本需要 JS 主线程执行的运算, 转交给另一条线程去完成.

这和 setTimeout 是同一个原理. 计数也不是 JS 主线程做的, 而是定时器触发线程做的.

参考

阮一峰 – Web Worker 使用教程

MDN – SharedWorker

Worker 基本使用

The Problem

假设我们有一个复杂运算 for loop 50亿次 (耗时 5 秒)

document.querySelector('h1').textContent = 'Hello World';
for (let i = 0; i < 5_000_000_000; i++) {} // 需要 5 秒钟
console.log('do something else');

如果我们让 JS 主线程来处理, 那么 UI 渲染就会慢 5 秒钟, 用户迟迟才会看见 Hello World 出现.

New Web Worker

这时我们可以开启 Web Worker, 它会创建另一条线程去处理这个 for loop. 然后我们把后续的代码变成一个 callback.

worker.js

for (let i = 0; i < 5_000_000_000; i++) {} // 需要 5 秒钟
self.postMessage('done'); // 通知主线程, 任务完成
self.close(); // 可以在子线程关闭, 也可以交由主线程关闭.

index.js

document.querySelector('h1').textContent = 'Hello World';
const worker = new Worker('./worker.js', { name: 'worker' });
// callback
worker.addEventListener('message', () => {
console.log('do something else');
worker.terminate(); // 关闭子线程
});

通过 addEventListener 注册 callback, 这样原本同步的代码就变成异步了.

Worker 沟通

主线程和子线程 (worker) 的沟通是通过 postMessage 和 addEventListener('message') 完成的.

postMessage 类似于 dispatchEvent 的意思.

主线程和子线程都可以 postMessage 和 listen message, 也都可以关闭子线程.

主线程也能监听子线程的错误

// index.ts – main thread
worker.postMessage('message'); // dispatch event to child thread
worker.addEventListener('message', () => {}); // listen event from child thread
worker.addEventListener('error', () => {}); // listen error from child thread
worker.terminate(); // close child thread // worker.ts – child thread
self.postMessage('done'); // dispatch event to main thread
self.addEventListener('message', () => {}); // listen event from main thread
self.close(); // close child thread (把自己关了)

Message Data Type

// index.ts
const worker = new Worker('./worker.js', { name: 'worker' });
const file = document.querySelector('input').files[0];
file.arrayBuffer().then(arrayBuffer => {
worker.postMessage({ value: 'value', buffer: arrayBuffer }, { transfer: [arrayBuffer] });
}); // worker.ts
self.addEventListener('message', event => {
const { value, buffer } = event.data;
});

两个点要注意

1. postMessage 可以传对象, 但是对象会被 deep copy.

2. ArrayBuffer 也会被 copy, 有时候 size 太大 copy 会很慢, 所以 postMessage 有个设置叫 transferable objects

声明 transfer 以后, ArrayBuffer 就转交给 worker 了 (no more copy, use cut instead), 这时主线程就不可以再读取 ArrayBuffer了.

Import Script in Worker

self.importScripts('/imported-script.js');

worker 内可以 import 其它的 script.

imported-script.js 也可以调用 self.postMessage 和主线程沟通.

而 worker 和 imported-script 要沟通则是通过全局变量 e.g. self.value = 'some value'.

SharedWorker

目前支持率不是很好, 以后才研究 TODO...

JavaScript – Web Worker的更多相关文章

  1. 深入理解javascript异步编程障眼法&&h5 web worker实现多线程

    0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 1 2 3 4 ...

  2. JavaScript多线程之HTML5 Web Worker

    在博主的前些文章Promise的前世今生和妙用技巧和JavaScript单线程和浏览器事件循环简述中都曾提到了HTML5 Web Worker这一个概念.在JavaScript单线程和浏览器事件循环简 ...

  3. Web Worker javascript多线程编程(一)

    什么是Web Worker? web worker 是运行在后台的 JavaScript,不占用浏览器自身线程,独立于其他脚本,可以提高应用的总体性能,并且提升用户体验. 一般来说Javascript ...

  4. Web Worker javascript多线程编程(二)

    Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...

  5. javascript 多线程Web Worker不引用外部js文件的方法

    最近在Android开发中 Webview通过调用JavascriptInterface的方式与App交互 在交互的过程中,有些App上的操作时间会比较长,Web中调用的话会造成程序假死的情况 于是想 ...

  6. 【转向Javascript系列】深入理解Web Worker

    本文首发在alloyteam团队博客,链接地址http://www.alloyteam.com/2015/11/deep-in-web-worker/ 上一篇文章<从setTimeout说事件循 ...

  7. 【转】Web Worker javascript多线程编程(一)

    原文:https://www.cnblogs.com/peakleo/p/6218823.html -------------------------------------------------- ...

  8. 过段时间逐步使用HTML5新增的web worker等内容

    想来快2017年了,2013年前的手机应该很少有人用了,以后逐渐使用HTML5新增的高级API吧. 先把web worker的内容再熟悉一下,因为微软虚拟学院的'面向有经验开发人员的 JavaScri ...

  9. web Worker使js实现‘多线程’?

    大家都知道js是单线程的,在上一段js执行结束之前,后面的js绝对不会执行,那么为什么标题说js实现‘多线程’,虽然说加了引号,可是标题也不能乱写不是,可恶的标题党? 姑且抛开标题不说,先说我们经常会 ...

  10. HTML5:web socket 和 web worker

    a:hover { cursor: pointer } 做练习遇到了一个选择题,是关于web worker的,问web worker会不会影响页面性能?补习功课之后,答案是不会影响. 查阅了相关资料学 ...

随机推荐

  1. 解决方案 | Claunch 如何更新配置文件

    1.问题 比如我的电脑上有Claunch 3.26版本(绿色版本),但是更新的时候如何保证我的新版本的图标.链接也更新是个问题. 官网说得比较模糊: 2.解决方法 打开复制data数据覆盖到新版本同样 ...

  2. ComfyUI进阶:Comfyroll插件 (一)

    ComfyUI进阶:Comfyroll插件 (一) 前言: 学习ComfyUI是一场持久战,而Comfyroll Studio 是一款功能强大的自定义节点集合,专为 ComfyUI 用户打造,旨在提供 ...

  3. vue 理解yarn start 和yarn dev的区别

    yarn dev,当文件变动后,会自动重启. yanr start不会自动重启 nodemon会监听文件变动,跟yarn dev和yarn start无关.

  4. [rCore学习笔记 06]运行Lib-OS

    QEMU运行第一章代码 切换分支 git checkout ch1 detail git checkout ch1 命令是用来切换到名为 ch1 的分支或者恢复工作目录中的文件到 ch1 提交的状态 ...

  5. .NET Core 3.x 基于AspectCore实现AOP,实现事务、缓存拦截器

    最近想给我的框架加一种功能,就是比如给一个方法加一个事务的特性Attribute,那这个方法就会启用事务处理.给一个方法加一个缓存特性,那这个方法就会进行缓存.这个也是网上说的面向切面编程AOP. A ...

  6. ABC361

    A link 先输出前\(k\)个,再输出\(x\),最后输出后面的. 点击查看代码 #include<bits/stdc++.h> using namespace std; int n, ...

  7. 《Programming from the Ground Up》阅读笔记:p88-p94

    <Programming from the Ground Up>学习第5天,p88-p94总结,总计7页. 一.技术总结 1.touppercase.s #PURPOSE: This pr ...

  8. mybatis:映射方式与SQL注入

    1.映射方式有两种,一种是resultType 这个是有一个实体类其成员与数据库中表字段一一对应,下例中就是User类对应了user表 <mapper namespace="com.e ...

  9. cgroup限制进程cpu

    编写一个死循环脚本 [root@workstation ~]# cat circle.sh #!/bin/bash a=1 while true do let a++ done 查看top 使用cgr ...

  10. 【Server】对象存储OSS - Minio

    官方文档: https://docs.min.io/docs/minio-quickstart-guide.html 看中文文档CV命令发现下不下来安装包,应该是地址问题 单击搭建非常简单,只有三个步 ...