Web worker 实践尝试

发布于 2022-03-05 14:50:24 字数 5430 浏览 1050 评论 0

概览:js 多线程

worker 技术,是让 js 在浏览器有多线程能力的一项技术。一个最直观的例子是看 whatwg 的例子
https://html.spec.whatwg.org/multipage/workers.html#a-background-number-crunching-worker
这个例子是开了一个线程在找素数,如果找到了,就通知前台,如果是直接写,UI线程的阻塞非常明显。

worker 的上下文

在worker里面的上下文与外面的不一样

interface WorkerGlobalScope : EventTarget {
  readonly attribute WorkerGlobalScope self;
  readonly attribute WorkerLocation location;
  readonly attribute WorkerNavigator navigator;
  void importScripts(USVString... urls);

  attribute OnErrorEventHandler onerror;
  attribute EventHandler onlanguagechange;
  attribute EventHandler onoffline;
  attribute EventHandler ononline;
  attribute EventHandler onrejectionhandled;
  attribute EventHandler onunhandledrejection;
};

可以看到,全局有三个对象self,location,navigator,一个函数importScripts,还有几个事件句柄。其中self对象指向全局对象本身,类似于我们熟悉的window。可以看到,worker与一般的浏览器环境最大的不同是没有DOMdocument.getElementById什么的就不要用了。然后与外面进行通讯是靠事件句柄。所以worker很适合计算量大异步的事情。

worker 与接口

这个例子告诉我们worker中可以用XMLHttpRequest对象。结合前面 #18 的工程化方案,我项目里面已经是用webpack基于commonjs打包的,而worker构造函数new Worker(params)里面的参数是js脚本的路径,所以我们需要worker-loader去帮我们屏蔽路径的问题。

代码分割问题

接上,worker-loader要载入的chunk都打包在一起,这会涉及到一个代码分割的问题,worker里面的代码与外面的上下文不一样,不能与外面共用代码。所以要尽量做到代码不重复载入,我在实践过程中的思路是这样的,用Promise,根据手机支持的情况,载入不同的代码分支,然后resolve不同的接口对象

let worker = null;
function getAPIObject(){
  return new Promise((resolve,reject)=>{
    if(window.Worker){
      require.ensure([],require=>{
        let Worker = require('worker!worker-chunk');
        worker = worker || new Worker(); //让worker只初始化一次
        resolve(worker);
      })
    }else{
      require.ensure([],require=>{
        let api = require('api-chunk');
        resolve(api);
      })
    }
  })
}

然后等首屏载入完之后,执行代码,让后台生成一个专门进行接口请求的的线程,处理报文封装的问题,主要是里面涉及到一个加密计算的的模块
然后整个请求的模块就从左边的模型变成右边的模型

+----------------------+                +----------------------+
|                      |                |                      |
| UI thread && encrypt |                |     UI thread        |
|                      |                |                      |
+--------^-------------+                +---------^------------+
         |                                        |
         |                                        |Promise
         |                              +---------v------------+
         |ajax                          |    worker(encrypt)   |
         |                              +---------^------------+
         |                                        |
+--------v-------------+                          |ajax
|                      |                +---------v------------+
|     service          |                |                      |
|                      |                |      service         |
+----------------------+                +----------------------+

jQuery历史遗留问题

因为历史代码的问题,我的接口请求模块是用jQuery写的,当时主要是为了方便管理ajax池。但前面也说了,worker中是没有DOM的,像这样的代码是绝对不行的。所以我参考
http://youmightnotneedjquery.com/ 中的ajax重写了一个很简单的接口请求代码。

调试的问题

因为项目的脚手架是参考 https://github.com/davezuko/react-redux-starter-kit 的。里面有一段代码是这样

  development : (config) => ({
    compiler_public_path : `http://${config.server_host}:${config.server_port}/`
  }),

可见在调试的时候,脚本载入的路径是一段完整的路径,比如你的debug机器是 192.168.1.2,端口8080,那么webpack给你生成的js引用代码就是

<script src="http://192.168.1.2:8080/chunk.hash.js"></script>

而不是

<script src="chunk.hash.js"></script>

然后我用手机真机调试的时候,一般会用代理(fiddler/charles)进行请求转发,顺便可以调用到桩数据,不用直接请求接口。代理的端口是8888,所以在浏览器看来,我打开了一个http://192.168.1.2:8888/的页面,却载入了一个http://192.168.1.2:8080/的脚本。一般的操作不会有问题,但是涉及到worker,会报DOM Exception 18错误。好吧,是跨域的问题,所以就修改成在手机上调试时public_path为空。

其他

  • 标准还提到传送消息时的对象共享的问题,一般用于前端图像处理,见 https://html.spec.whatwg.org/multipage/workers.html#module-worker-example
  • 在多页面应用中应该要用sharedworker
  • 同样是多线程,在node端,可以用child_process模块
    以上,由于还本人没有进行实践,就不多写了,挖个坑以后慢慢研究。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

qq_aHcEbj

文章 0 评论 0

寄与心

文章 0 评论 0

13545243122

文章 0 评论 0

流星番茄

文章 0 评论 0

春庭雪

文章 0 评论 0

潮男不是我

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文