聊聊 Web Workers 吧
背景
为啥突然想学习 Web Worker 了呢,因为我在某金上看到了一篇文章,而那篇文章有个评论说 Web Worker 实现起来很丝滑,我在想是要怎么实现呢,于是就开启了探究 Web Worker 之旅……
阅读 MDN
以下是 MDN 的相关解释:
用 Web Workers,Web 应用程序可以在独立于主线程的后台线程中,运行一个脚本操作。这样做的好处是可以在独立线程中执行费时的处理任务,从而允许主线程(通常是 UI 线程)不会因此被阻塞/放慢。
显然使用 Web Worker 是有好处的,就是可以将任务重的计算在不阻塞主线程的情况下继续运行,实现性能的提升(不过也不宜过度使用,后面会说到)。
Web Worker 可分为 Dedicated Workers、Shared Workers、Service Workers、Chrome Workers 以及音频 Workers,后面两个我负责的项目中使用场景不多,就不展开了,主要介绍前三个 Web Workers。
Dedicated Workers
定义、使用
Dedicated Workers 使用构造函数 Worker()
创建一个 Worker 对象,构造函数接受一个 JavaScript 文件 URL,这个文件包含了将在 worker 线程中运行的代码,具体例子:
启动/运行 Web Worker
首先要知道 Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。所以如果本地创建了一个 html 文件和 js 文件,直接在浏览器打开该 html 文件,Web Worker 是无效的,比如我打开的是file:///Users/xxx/Desktop/aaa/aaa.html
,内部引入的 js 包含了上面 Web Worker 相关的 JS 代码,那么控制台会报出一个错误
所以如果想在本地调试,需要将文件 serve 起来,我是用的是 python 命令:python -m SimpleHTTPServer 8000
。
Chrome Debug
代码上实现了 Web Worker,也确实能正常运行,那么我怎么知道 worker 到底在哪里呢,我的页面里面有几个 workers 呢?
打开 Chrome -> CMD+SHIFT+I -> Sources Tab -> Page,然后就可以看到有多少个 Web Worker 以及具体 Web Worker 的脚本。
关闭 Web Worker
使用完毕,为了节省系统资源,必须关闭 Worker。
对于 Dedicated Workers 而言,关闭意味着在 chrome 的 sources tab 也会消失:
Shared Workers
Shared Workers 跟 Dedicated Workers 使用上是基本一致的,可能更复杂一些,Shared Workers 可被不同的窗体的多个脚本运行,例如 IFrames 等。代码举例🌰:
在 Chrome 的 debug 方式也不一样,打开chrome://inspect
,可以看到很多 navigations,其中有一个叫做Shared Workers
,那这里是可以看到打开的网页有哪些是使用了 Shared Workers 的。
Service Workers
说实话,我本人接触的第一个 Web Workers 就是 Service Worker,以前有一个项目是给工人在工地上做工时应用,工地也没有网络,或者说信号极差,所以对离线要求也比较高,当时调研过 Service Worker,但是使用起来有点复杂的,再加上当时不满足浏览器的兼容性,所以就使用了另外一种方式indexdb
。
根据文档,Service Worker 可以创建有效的离线体验,拦截网络请求,以及根据网络是否可用采取合适的行动,更新驻留在服务器上的资源。
Angular 框架是实现了 Service Worker 的,而其中也有一些 bug(记得是版本 7,现在有可能已经修复了,很久没用过 Angular 了😅),如果开启了之后,可能会对版本的更新有一定的影响,话说至今我都不明白为啥那个项目要开启 Service Worker,大家也米有离线的需求额……
在 Chrome 浏览器也是可以很方便地 debug,在 Application tab 的子菜单里面:
开发注意的地方/限制
前面也提到了,Web Workers 不能通过本地文件的方式运行,只能通过网络,否则无法执行;
同源:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源;
DOM 限制:可能很多人特别开心,那页面渲染的性能瓶颈是不是就能通过 Web Workers 来解决了呢,还是图样图森破啊,Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用 document、window、parent 这些对象。
但是还是有很多 Web API 在 Web Workers 中是可以访问的,比如使用 XMLHttpRequest 来访问网络,可以使用 navigator 对象和 location 对象等,所以别灰心,大多数 API 也是可以用的。
思考
虽然学习了 Web Workers,也知道如何使用,但是目前来讲好像使用 Web Workers 解决问题的项目不多,通过搜索引擎发现很多库/工具都实现了 Web Workers 呢,我个人还是很看好 Web Workers 滴:
🌟: useWorker
🌟: Threadjs
🌟: worker-dom
欢迎大家一起交流哦🍺🍺🍺
References:
http://www.ruanyifeng.com/blog/2018/07/web-worker.html
https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers
版权声明: 本文为 InfoQ 作者【Faye】的原创文章。
原文链接:【http://xie.infoq.cn/article/d18548286d06e314d12db3afd】。文章转载请联系作者。
评论