为了账号安全,请及时绑定邮箱和手机立即绑定

初探 HTML5 Web Workers

标签:
Html5 JavaScript

原文:初探 HTML5 Web Workers

一、Web Workers是什么

Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,他们可以使用XMLHttpRequest执行 I/O (尽管responseXML和通道属性总是为空)。一旦创建, 一个worker 可以将消息发送到创建它的JavaScript代码, 通过将消息发布到该代码指定的事件处理程序 (反之亦然)。 —— MDN

众所周知,JavaScript是单线程的编程语言,也就是说,当我们在页面中进行一个较为耗时的计算的JavaScript代码时,在这段代码执行完毕之前,页面是无法响应用户操作的。也正是出于这个原因,HTML5为我们提供了 Web Workers 以解决这种问题,当我们需要在JavaScript中来进行耗时的计算或诸如此类的问题时,我们可以使用 Web Workers 在浏览器的后台启动一个独里的 Worker 线程来专门负责这段代码的运行,而不会阻碍后面代码的运行。

二、Web Workers的使用

1. 实例化一个 Worker

实例化运行一个 Worker 很简单,我们只需要 new 一个 Worker 全局对象即可。

var worker = new Worker('./worker.js')

它接受一个 filepathname String 参数,用于指定 Worker 脚本文件的路径。然后我们就可以在 worker.js 中写下一些代码:

console.log('my_WOEKER:', 'srtian')

另外,通过URL.createObjectURL()创建URL对象,也可以实现创建内嵌的worker:

var myTask = `    var i = 0;    var timedCount = () => {
        i = i+1;
        postMessage(i);
        setTimeout(timedCount, 1000);
    }
    timedCount();
`;var myblob = new Blob([myTask]);var myWorker = new Worker(window.URL.createObjectURL(myblob));

需要注意的是,传入 Worker 构造函数的参数 URI 必须遵循同源策略。

此外因为Worker线程的创建的是异步的,所以主线程代码不会阻塞在这里等待 worker 线程去加载、执行指定的脚本文件,而是会立即向下继续执行后面代码这点也需要注意。

2. 数据通信

当我们实例化一个 Worker 线程后,Worker不会相互,或者与主程序共享任何作用域或资源——那会将所有的多线程编程的噩梦带到我们面前——取而代之的是一种连接它们的基本事件消息机制。因此他们需要通过基于事件监听机制的message来进行通信,我们在new Worker()后悔返回一个实例对象,它包含了一个postMessage的方法,我们可以通过调用这个方法来给worker线程传递信息,我们也可以给这个对象监听事件,从而在worker线程中出发事件通信的时候能接收到数据。

var worker = new worker('./worker.js')
worker.addEventListener('message', function(e) {    console.log('worker receive:', e.data )
}
worker.postMessage('hello worker,this is main.js')

然后在worker.js这个脚本中,我们就可以调用全局函数postMessage和全局的onmessage赋值来发送和监听数据和事件了。

// 监听事件onmessage = function (e) {  console.log('WORKER RECEIVE:', e.data);  // 发送数据事件
  postMessage('Hello, this is worker.js');
}

需要注意的是 worker 支持 JavaScript 中所有类型的数据传递,可以传递一个 Object 数据;但这里的数据传递(主要是 Object 类型)并不是共享,而是复制。发送端的数据和接收端的数据是复制而来,并不指向同一个对象,此外这里的复制不是简单的拷贝,而是通过两端的序列化/解序列化来实现的,一般来说浏览器会通过 JSON 编码/解码;当然,这里的更多细节部分会由浏览器来处理,我们并不需要关心这些,只需要明白两端的数据是复制而来,互相独立的就行了。

3. 错误处理机制

当 worker 出现运行中错误时,它的 事件处理函数会被调用。它会收到一个扩展了 ErrorEvent 接口的名为 error的事件。

该事件不会冒泡并且可以被取消;为了防止触发默认动作,worker 可以调用错误事件的 preventDefault() 方法。

错误事件有以下三个用户关心的字段:

  • message: 可读性良好的错误消息。

  • filename: 发生错误的脚本文件名。

  • lineno: 发生错误时所在脚本文件的行号。

实际操作如下:

var worker = new Worker('./worker.js');// 监听消息事件worker.addEventListener('message', function (e) {  console.log('MAIN RECEIVE: ', e.data);
});// 也可以使用 onMessage 来监听事件:// 监听 error 事件worker.addEventListener('error', function (e) {  console.log('MAIN ERROR:', e);  console.log('MAIN ERROR:', 'filename:' + e.filename + '---message:' + e.message + '---lineno:' + e.lineno);
});// 触发事件,传递信息给 Workerworker.postMessage({  m: 'Hello Worker, this is main.js'});

4. 终止 Worker

当我们在不需要 Worker 继续运行时,我就需要终止掉这个线程,这时候我们就可以调用 worker 的 terminate 方法:

worker.terminate()

worker 线程会被立即杀死,不会有任何机会让它完成自己的操作或清理工作。

而在worker线程中,workers 也可以调用自己的 close  方法进行关闭:

close()

三. Web Workers的兼容

由于Web Workers是HTML5所提供的,因此从兼容性上来说,还是需要注意的。总的兼容情况如下图所示:

webp

image


图片来源:https://caniuse.com/#feat=webworkers


我们可以看到,虽然web worker很不错,但如果我们的代码执行在较老的浏览器中时,是缺乏支持的。但由于worker是一个API而不是语法,因此我门还是可以去填补它的。

这一块的详情可以去看——《你不知道的JavaScript中卷》关于 web worker 的那一节。

四、Web Workers支持的JavaScript特性

由于在 Worker 线程的运行环境中没有 window 全局对象,也无法访问 DOM 对象,所以一般来说我们在这只能执行纯JavaScript的计算操作,当然1我们那:

  • setTimeout(), clearTimeout(), setInterval(), clearInterval():有了设计个函数,就可以在 Worker 线程中执行定时操作了;

  • XMLHttpRequest 对象:意味着我们可以在 Worker 线程中执行 ajax 请求;

  • navigator 对象:可以获取到 ppName,appVersion,platform,userAgent 等信息;

  • location 对象(只读):可以获取到有关当前 URL 的信息;

  • 应用缓存

  • 使用 importScripts() 引入外部 script

  • 创建其他的 Web Worker

五、Web Worker 的实践

总的来说,Web Worker为我们带来了强大的计算能力,我们可以加载一个JavaScript进行大量的复杂计算,而用不挂起主进程。并通过postMessage,onmessage进行通信,这也解决了大量计算对UI渲染的阻塞问题。

应用场景

1、数学运算

Web Worker最简单的应用应该就是用来进行后台计算了,这对CPU密集型的场景再适合不过了。

2、图像处理

通过使用从 canvas 中获取的数据,可以把图像分割成几个不同的区域并且把它们推送给并行的不同Workers来做计算,对图像进行像素级的处理,再把处理完成的图像数据返回给主页面。

3、大数据的处理

目前mvvm框架越来越普及,基于数据驱动的开发模式也越愈发流行,未来大数据的处理也可能转向到前台,因此我们将大数据的处理交给在Web Worker也是很好的。

4. 数据预处理

为优化的网站或 web 应用的数据加载时长,我们可以使用 Web Worker 预先获取一些数据,存储起来以备后续使用,因为它绝不会影响应用的 UI 体验。

5. 大量的 ajax 请求或者网络服务轮询

由于在主线程中每启动一个XMLHttpRequest请求都会消耗资源,虽然在请求过程中浏览器另外开了一个线程,但是在交互过程中还是需要消耗主线程资源;而使用worker则不会过多占用主线程,只是启动worker过程时比较耗资源。

参考资料:

  1. 《你不知道的JavaScript中卷》

  2. https://juejin.im/post/59c1b3645188250ea1502e46

  3. https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers

  4. https://qiutc.me/post/the-multithread-in-javascript-web-worker.html

  5. https://juejin.im/post/5a90233bf265da4e92683de3



作者:srtian
链接:https://www.jianshu.com/p/523055dbeb3e


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消