web worker 扫盲篇

什么是woker

官方的解释是这样的:

worker是一个对象,通过构造函数Worker创建,参数就是一个js文件的路径;文件中的js代码将运行在主线程之外的worker线程;

var jsFileURI = JS_FILE_PATH;  // js文件路径

var worker = new Worker(jsFileURI);

worker运行在另一个全局上下文中(self),这个全局上下文不同于window,所以不能在woker中访问window和DOM;

该线程分为两种:dedicated workershared worker;dedicated worker只能被初始化它的js上下文中使用;shared worker可以在多个js上下文中使用。通常使用的worker是dedicated worker,它的工作情况可以通过chrome的调试工具查看。

为什么引入woker?

前端开发者应该知道浏览器中JS和UI公用一个线程,JS计算过程中,不能响应UI;如果遇到计算量比较大的任务,如操作图像像素时,会造成用户行为得不到响应。Web Worker 是为了解决 JavaScript 在浏览器环境中没有多线程的问题。支持 Web Worker 的浏览器会额外提供一个 JavaScript Runtime 供 Web Worker 使用。它的最佳使用场景是执行一些开销较大的数据处理或计算任务。

woker是怎么工作的?

Web Worker 使用起来非常简单,在“主线程”中执行如下操作即可创建一个 Worker 实例,通过监听 onmessage 事件获取消息,通过 postMessage 发送消息:

“主线程”和Worker 之间通过 postMessage 发送消息,通过监听 onmessage 事件来接收消息,从而实现二者的通信。

如下图所示:

核心代码如下:

主线程中代码

var worker = new Worker('worker.js');
worker.onmessage = function (e) {
    var data = e.data;
}
var messageData = {
    message: 'hello worker!'
};
worker.postMessage(messageData);

worker.js 中的代码如下:

self.onmessage = function(e) {
    var messages = e.data;  // e.data为{message: 'hello worker!'}
    var workerResult = {};
    // do something
    ...
    postMessage(workerResult);
}

使用woker的几个tips

(1)使用多少个worker?

遇到复杂的计算,需要开启多少worker才合适呢?一般的做法是参考navigator.hardwareConcurrency 这个属性,它表示机器支持的并行最大任务数。还有一种动态检测 Worker 数量的方法,有兴趣的话可以看:https://github.com/oftn-oswg/core-estimator。

(2)优化woker与主线程通信开销

该段主要参考百度地图技术博客(https://mp.weixin.qq.com/mp/getmasssendmsg?__biz=MzIzNDE0NjMzOQ==#wechat_webview_type=1&wechat_redirect)。

Worker 与“主线程”之间的数据传递默认是通过结构化克隆(Structured Clone)完成的。数据量较大时,克隆过程会比较耗时,这会影响 postMessage 和 onmessage 函数的执行时间。

解决的办法一是先通过 JSON.stringify 将对象序列化,接收之后再用 JSON.parse 还原。因为:stringfiy + 传递字符串的耗时 < 传递对象的耗时 。

代码如下:

// 操作像素
    var imageData = context.createImageData(img.width, img.height);
    var work = new Worker('./cal.js');
    var data = {
        data: imageData.data,
        width: imageData.width,
        height: imageData.height
    };
    // 将传递的参数转换成字符串
    work.postMessage(JSON.stringify(data));

还有一种避开克隆传值的方法,就是使用Transferable Objects,主要是采用二进制的存储方式,采用地址引用,解决数据交换的实时性问题;Transferable Objects支持的常用数据类型有ArrayBuffer和ImageBitmap;

使用方法如下:

   // 操作像素
    var imageData = context.createImageData(img.width, img.height);
    var work = new Worker('./cal.js');
    // 转化为类型数组进行传递
    var int8s = new Int8Array(imageData.data);
    var data = {
        data: int8s,
        width: imageData.width,
        height: imageData.height
    };
    // 在postMessage方法的第二个参数中指定transferList
    work.postMessage(data, [data.data.buffer]);

经测试,使用arrayBuffer之后,传递数据所需的时间为1ms,极大地提高了数据传输的效率。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大内老A

WCF技术剖析之二十七: 如何将一个服务发布成WSDL[编程篇]

对于WCF服务端元数据架构体系来说,通过MetadataExporter将服务的终结点导出成MetadataSet(参考《如何导出WCF服务的元数据》),仅仅是...

21470
来自专栏安恒网络空间安全讲武堂

CSP总结及CTF实例分析

本文作者:HeartSky 最近各大比赛中 CSP 绕过的题目突然多了起来,自己也尝试着总结下 What is CSP? > The new Content-S...

57260
来自专栏同步博客

掀开断点续传那一层面纱(下载篇)

  这一篇文章主要介绍的是http协议下载时的断点续传,详细到各个步骤。主要步骤有:DNS查找、TCP三次握手、http请求发送、TCP协议数据传输、暂停后的状...

15440
来自专栏编程

小白爬虫之爬虫快跑,多进程和多线程

使用多线程时好像在目录切换的问题上存在问题,可以给线程加个锁试试 Hello 大家好!我又来了。 你是不是发现下载图片速度特别慢、难以忍受啊!对于这种问题 一般...

22670
来自专栏更流畅、简洁的软件开发方式

【自然框架】重新整理后的自然框架源码!

  整理后的自然框架源码,有九个项目,可以看下面的脑图,带“对号”的表示是一个独立的项目。后面的是主要内容。 欢迎下载http://www.naturefw....

24580
来自专栏前端说吧

Gulp安装流程、使用方法及cmd常用命令导览

45260
来自专栏成猿之路

关于Java Tomcat 内存溢出排查心得分享

27730
来自专栏专注于主流技术和业务

axios2教程

axios 是一个基于 promise 的 HTTP 库,用于浏览器和node.js的http客户端,支持拦截请求和响应,自动转换 JSON 数据, 客户端支持...

1.1K20
来自专栏跟着阿笨一起玩NET

visual studio xcopy /exclude测试

http://files.cnblogs.com/files/zfanlong1314/exclude%E6%B5%8B%E8%AF%95.zipxcopy 提...

8210
来自专栏Danny的专栏

【SSH快速进阶】——探索Hibernate对象的三种状态:Transient、Persistent、Detached

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

11320

扫码关注云+社区

领取腾讯云代金券