• 主页
  • 归档
  • 分类
  • 照片墙
所有文章 友情链接 关于我

  • 主页
  • 归档
  • 分类
  • 照片墙
  1. 1. 基本用法
  2. 2. 线程通信
  3. 3. 数据转移
  4. 4. 可能的错误
  5. 5. 在webpack中使用
    1. 5.1. 同源策略

Web-Workers

2019-09-21 19:22:06
总字数 1.3k
预计阅读时间 5 分钟

在较早的时候,JavaScript本身是没有多线程的,如果执行耗时长的同步操作会造成页面假死影响用户体验
HTML5提供了Web Workers API,可以解决这个问题

并非所有耗时操作都可以用异步解决
比如密集的计算或者一些高延迟的任务

简单来说,Web Workers可以在一个子线程当中运行一个js脚本,这个js脚本当中可能有一些耗时的操作
从而保证主线程不会被阻塞
并且提供了一些机制在主子线程之间进行通信

基本用法

1
var wk = new Worker('./worker.js', {})

第一个参数是worker将执行的脚本的URL,它必须遵守同源策略。
第二个参数是配置项(可选),有以下三个有效项

  • type:指定要创建的工作进程类型的名称。如果未指定,则默认使用classic。
  • credentials:指定要用于工作进程的凭据类型的名称。如果未指定,或者类型为classic,则使用的默认值为省略(不需要凭据)。
  • name:一个字符串,指定表示工作进程作用域的专用WorkerGlobalScope的标识名称,主要用于调试。

线程通信

不同的线程之间的通信是采用事件机制触发的,使用message事件进行通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// main.js
console.log('这里是主线程')
var wk = new Worker('./js/worker.js', {})
wk.onmessage = event => {
// 这里用来接收子线程发过来的消息
console.log(event.data)
}
wk.onerror = err => {
// 子线程抛出的错误
wk.terminate() // 立即终止worker
console.error(err)
}
let btn = document.getElementById('send-msg')
btn.addEventListener('click', function(){
// 向子线程发送消息
wk.postMessage({msg: 'HOHO~'}) // 可以是任意的对象
})
console.log('这里还是主线程')

子线程对应的js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// worker.js
console.log('这里是子线程')
let i = 1
function simpleCount() {
self.postMessage(++i)
if(i>100) {
self.close() // 子线程关闭自己
}
setTimeout(simpleCount, 1000)
}
simpleCount()
self.onmessage = event => {
console.log(event.data)
}
  • 子线程中的self代表线程自身,如同非严格模式下主线程中this指向window
    非严格模式下的子线程this指向这个self
  • 子线程无法读取主线程所在网页的DOM对象,也无法使用document、window、parent这些对象。
    但是,子线程可以navigator对象和location(只读)对象
  • postMessage的对象传递是值拷贝,而且是深拷贝,并非地址拷贝
    (实际实现的方式是先进行序列化,再进行反序列化)
  • 子线程中有可以加载脚本的函数 importScripts(‘script1.js’, ‘script2.js’)
  • 子线程中不能执行诸如alert confirm等阻塞性的函数
  • 子线程执行close或者主线程对worker执行terminate会结束子线程
    Worker对象如果没有引用指向,则会被JavaScript的垃圾回收器回收
    其他情况下子线程即使空闲也不会停止,随时可以响应主线程的通信
  • wk.onmessage同样也可以使用wk.addEventListener('message', function(){...})

数据转移

主线程与子线程之间可以交换二进制数据,比如ArrayBuffer对象
但是拷贝方式发送数据会造成严重的性能问题
因此postMessage可以接受第二个参数,用来把二进制数据直接转移给子线程
(一旦转移,主线程将无法再使用这些数据)

1
2
3
4
5
6
let obj = {
ab: new ArrayBuffer(10)
}
console.log('转交前长度', obj.ab.byteLength) // 10
wk.postMessage(obj,[obj.ab])
console.log('转交后长度', obj.ab.byteLength) // 0

在子线程当中同样通过event.data拿到该对象

1
2
3
self.onmessage = function(event) {
console.log(event.data.ab)
}

可以这样转移的对象须实现Transferable接口,这只是一个标记接口
实现该接口的类型有ArrayBuffer、MessagePort、ImageBitmap

可能的错误

  • 如果文档不允许启动worker,则会引发SecurityError
  • 如果脚本之一的MIME类型为 text/csv, image/*, video/*,或 audio/*, 则会引发NetworkError。它应该始终是 text/javascript。
  • 如果url无法解析,则引发SyntaxError。

在webpack中使用

需要引入work-loader这个加载器

1
2
3
4
let MyWorker = require('worker-loader!./test.js')
// 引入的这个对象可以直接当做Worker对象来用
let wk = new MyWorker()
wk.postMessage('test')

或者在webpack的配置文件当中添加规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
module: {
rules: [
{
// 匹配 *.worker.js
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
name: '[name]:[hash:8].js',
// inline: true,
// fallback: false
// publicPath: '/scripts/workers/'
}
}
}
]
}
}

同源策略

Web Worker严格遵守同源策略,如果webpack的静态资源与应用代码不是同源的,那么很有可能就被浏览器给墙掉了,而且这种场景也经常发生。
对于Web Worker遇到这种情况,有两种解决方案

  1. 通过设置worker-loader的选项参数inline把worker内联成blob数据格式,而不再是通过下载脚本文件的方式来使用worker
  2. 通过设置worker-loader的选项参数publicPath来重写掉worker脚本的下载url,当然脚本也要存放到同样的位置
  • JavaScript
  • Web Worker
  • JavaScript

扫一扫,分享到微信

dart初见(1)
xargs命令 
© 2024 夏夜梦星辰
鲁ICP备19028444号
Power By Hexo
  • 所有文章
  • 友情链接
  • 关于我
{{searchItem.query}}
标签: 分类:
  • maven
  • 持续集成
  • JMS
  • 线程
  • JavaScript
  • ECMAScript6
  • 单元测试
  • Promise
  • Web Worker
  • 函数
  • prototype
  • 模块化
  • 正则表达式
  • 数据库
  • MongoDB
  • 索引
  • 集群
  • 全文检索
  • flutter
  • dart
  • git
  • 版本控制
  • linux
  • shell
  • docker
  • nginx
  • jenkins
  • opencv
  • vim
  • react
  • react native
  • 前端
  • css
  • HTML5
  • Hexo
  • sass
  • Three.js
  • TypeScript
  • Vue
  • 组件化
  • base64
  • webpack
  • nodejs
  • gulp
  • TensorFlow
  • 机器学习
  • 算法
  • 动态规划
  • 数据结构
  • Java
  • JavaScript
  • MongoDB
  • flutter
  • Git
  • linux
  • react
  • 前端杂烩
  • 男生女生
  • 算法
  • 十年饮冰,难凉热血
  • †少女癌†
  • 猫与向日葵
  • coderfun
  • JENKINS
  • API管理后台
愿你最终能接纳每一面每一种的自己
独自活着便是团圆