Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

都说前端学不动了 - 来聊聊 Web Worker 吧 #51

Open
fayeah opened this issue Jul 21, 2021 · 0 comments
Open

都说前端学不动了 - 来聊聊 Web Worker 吧 #51

fayeah opened this issue Jul 21, 2021 · 0 comments
Labels
UI UI test framework/tool

Comments

@fayeah
Copy link
Owner

fayeah commented Jul 21, 2021

背景

为啥突然想学习 Web Worker 了呢,因为我在某金上看到了一篇文章,而那篇文章有个评论说 Web Worker 实现起来很丝滑,我在想是要怎么实现呢,于是就开启了探究 Web Worker 之旅……

阅读 MDN

一般来讲,对于前端领域看到一个陌生又熟悉的词汇,Google之后都可以看到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 线程中运行的代码,具体例子:

// main.js
var myWorker = new Worker('./worker.js');

// worker.js,里面是worker线程运行的任务(执行的计算比较重的代码)
onmessage = function(e) {
  console.log('Message received from main script');
  var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
  console.log('Posting message back to main script');
  postMessage(workerResult);
}

启动/运行 Web Worker

首先要知道 Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。所以如果本地创建了一个 html 文件和 js 文件,直接在浏览器打开该 html 文件,Web Worker 是无效的,比如我打开的是file:///Users/xxx/Desktop/aaa/aaa.html,内部引入的js包含了上面 Web Worker 相关的 JS 代码,那么控制台会报出一个错误

image

所以如果想在本地调试,需要将文件serve起来,我是用的是python命令:python -m SimpleHTTPServer 8000

Chrome Debug

代码上实现了 Web Worker,也确实能正常运行,那么我怎么知道worker到底在哪里呢,我的页面里面有几个workers呢?

image

打开 Chrome -> CMD+SHIFT+I -> Sources Tab -> Page,然后就可以看到有多少个 Web Worker 以及具体 Web Worker 的脚本。

关闭 Web Worker

使用完毕,为了节省系统资源,必须关闭 Worker。

// 主线程
worker.terminate();
// Worker 线程
self.close();

对于 Dedicated Workers而言,关闭意味着在 chrome 的sources tab也会消失:

web-worker

Shared Workers

Shared Workers 跟 Dedicated Workers使用上是基本一致的,可能更复杂一些,Shared Workers 可被不同的窗体的多个脚本运行,例如IFrames等。代码举例🌰:

// main.js
if (!!window.SharedWorker) {
  var myWorker = new SharedWorker("worker.js");

  first.onchange = function() {
    myWorker.port.postMessage([first.value, second.value]);
    console.log('Message posted to worker');
  }

  second.onchange = function() {
    myWorker.port.postMessage([first.value, second.value]);
    console.log('Message posted to worker');
  }

  myWorker.port.onmessage = function(e) {
    result1.textContent = e.data;
    console.log('Message received from worker');
    console.log(e.lastEventId);
  }
}

// worker.js
onconnect = function(e) {
  var port = e.ports[0];
  port.onmessage = function(e) {
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }
}

在Chrome的debug方式也不一样,打开chrome://inspect,可以看到很多navigations,其中有一个叫做Shared Workers,那这里是可以看到打开的网页有哪些是使用了 Shared Workers的。

image

Service Workers

说实话,我本人接触的第一个Web Workers就是Service Worker,以前有一个项目是给工人在工地上做工时应用,工地也没有网络,或者说信号极差,所以对离线要求也比较高,当时调研过 Service Worker,但是使用起来有点复杂的,再加上当时不满足浏览器的兼容性,所以就使用了另外一种方式indexdb

根据文档,Service Worker 可以创建有效的离线体验,拦截网络请求,以及根据网络是否可用采取合适的行动,更新驻留在服务器上的资源。

Angular框架是实现了 Service Worker的,而其中也有一些bug(记得是版本7,现在有可能已经修复了,很久没用过Angular了😅),如果开启了之后,可能会对版本的更新有一定的影响,话说至今我都不明白为啥那个项目要开启Service Worker,大家也米有离线的需求额……

在Chrome浏览器也是可以很方便地debug,在Application tab的子菜单里面:

image

开发注意的地方/限制

  1. 前面也提到了,Web Workers 不能通过本地文件的方式运行,只能通过网络,否则无法执行;
  2. 同源:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源;
  3. 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
🌟: react-worker-image
🌟: worker-dom

欢迎大家一起交流哦🍺🍺🍺

References:

@fayeah fayeah changed the title 都说前端学不动了 - 来聊聊 Web Worker吧 都说前端学不动了 - 来聊聊 Web Worker 吧 Jul 21, 2021
@fayeah fayeah added the UI UI test framework/tool label Aug 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
UI UI test framework/tool
Projects
None yet
Development

No branches or pull requests

1 participant