• 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,
             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,
             imageData.width,
            height: imageData.height
        };
        // 在postMessage方法的第二个参数中指定transferList
        work.postMessage(data, [data.data.buffer]);

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

  • 相关阅读:
    js,jQuery实现可关闭悬浮框广告特效,兼容(谷歌,火狐,Ie)
    各种选择框jQuery的选中方法
    表单校验demo
    两种方法实现城市级联菜单
    树形菜单
    匿名函数和鼠标移入移除事件
    多线程实例
    Lock锁
    Oracle语句
    Java NIO
  • 原文地址:https://www.cnblogs.com/wmhuang/p/6913468.html
Copyright © 2020-2023  润新知