多线程worker

本文档中的worker仅限于浏览器模式中的HTML5模式运行支持,LayaNative打包APP方案中暂不支持worker

从传统意义上来说,浏览器是单线程的,它们会强制应用程序中的所有脚本一起在单个 UI 线程中运行。虽然你可以通过使用文档对象模型 (DOM) 事件和 setTimeout等API 造成一种多个任务同时在运行的假象,但只需一个计算密集型任务就会使用户体验急转直下。在html5引入了worker的功能,通过使用Web Worker, 我们可以在浏览器后台运行JavaScript, 而不占用浏览器自身线程。Web Worker可以提高应用的总体性能,并且提升用户体验。线程可以执行任务而不干扰用户界面。

原生worker

web worker分为两种,专用线程dedicated web worker,以及共享线程shared web worker。 Dedicated web worker随当前页面的关闭而结束;这意味着Dedicated web worker只能被创建它的页面访问。与之相对应的Shared web worker可以被多个页面访问。但是web worker有些限制,并非所有的接口和方法都能使用。

  • Web Worker无法访问DOM节点;

  • Web Worker无法访问全局变量或是全局函数;

  • Web Worker无法调用alert()或者confirm之类的函数;

  • Web Worker无法访问window、document之类的浏览器全局变量;

    workder 支持的函数 页面提供了一个 worker 支持的全局函数列表。开发者可以自己看下相应的方法。

方法概述

构造函数Worker()

该构造函数创建一个 web worker,它能执行位于指定 URL 上的脚本。脚本必须遵循 同源策略

postMessage():

向 worker 的内部作用域内传递消息。该方法接收一个单独的参数,即要传递给 worker 的数据。数据可以是任何值或者是经过结构化拷贝算法处理过的 JavaScript 对象,换句话说,可以包含循环引用。

#参数
  • aMessage

    传输给 worker 的对象;它将包含于传递给 onmessage 处理函数的事件对象中的 data 字段内。你可以传递任意值或是经过结构化拷贝算法处理过的 JavaScript 对象,即可以包含循环引用。

  • transferList

    一个可选的对象数组,用于转让它们的所有权。如果一个对象的所有权被转让,那么它在原来的上下文内将不可使用,而只能在转让到的 worker 内可用。

terminate()

立即终止 worker。该方法不会给 worker 留下任何完成操作的机会;就是简单的立即停止

属性

Property Type Description
onmessage EventListener 一个事件监听函数,每当拥有message属性的MessageEvent从worker中冒泡出来时就会执行该函数。事件的data属性存有消息内容。
onerror EventListener 一个事件监听函数,每当类型为errorErrorEvent 从 worker 中冒泡出来时就会执行该函数。

下面我们用原生js看下如何使用。

新建一个js文件,放到index.html中。代码如下:

var myWorker = new Worker("js/my_task.js");
myWorker.onmessage = function (oEvent) {
    console.log("Called back by the worker!\n");
};
myWorker.postMessage("start"); // start the worker.

新建一个my_task.js文件,放到js文件夹下,代码如下:

self.addEventListener('message', function (e) {
    var xmlreq = new XMLHttpRequest();
    xmlreq.responseType = "text";
    xmlreq.onload = function (e) {
        var data = e.currentTarget.response;
        self.postMessage(data);
    }
    xmlreq.open("get","../atlas/comp.json");
    xmlreq.send()
}, false);

这个例子是在worker中进行加载文件,加载完毕传给主进程,运行这个例子可以在浏览器控制台看到数据输出来。

var myWorker = new Worker("my_task.js")实例化一个worker,传进去一个js文件,通过myWorker.postMessage("start")通知worker线程启动。

self.addEventListener('message',xxx)监听主线程通知的消息。

self.postMessage(data);发送数据给主线程。

注意:web worker不支持文件协议,所以直接打开是不能运行的,开发者可以配合IDE内置的服务器,通过网址来运行就可以看到效果。打开控制台可以看到数据已经打印出来了。

Laya中应用

在LayaAir3.0中内部封装了worker,解决加载解码图片卡顿现象,开发者可以打开开关,也可以自定义worker,解决项目中耗费cpu的地方,下面我们分别来介绍下。

新建一个项目,为了方便显示,我们新建一个ui项目。简单的调用接口如下:

class LayaUISample {
    constructor() {
        //初始化引擎
        Laya.init(600,400,Laya.WebGL);
        //设置Laya提供的worker.js路径
        Laya.WorkerLoader.workerPath = "libs/worker.js";
        //开启worker线程
        Laya.WorkerLoader.enable = true;
        //加载引擎需要的资源
        Laya.loader.load("../atlas/comp.atlas",Laya.Handler.create(this,this.onLoaded));
    }
    private onLoaded():void{
        //实例UI界面
        var testView:ui.test.TestPageUI = new ui.test.TestPageUI();
        Laya.stage.addChild(testView);
    }
}
new LayaUISample;

WorkerLoader.workerPath = "libs/worker.js";

设置worker.js的路径,这个worker.js是Laya官方提供的,我们把他拷贝复制到我们自己设置的路径,这个js在Laya的引擎库当中。我这里设置的是libs下。

WorkerLoader.enable = true;

开启worker模式加载解码图片,大大解放了主线程解码的压力。

上面的方法是2.0官方的解码的做法,在LayaAir3.0中我们也可以自定义worker来优化项目当中的耗费cpu的地方。

下面通过简单的例子来演示下用法。我们可以把教程开头的js脚本移植过来。

var worker:any = new Laya.Browser.window.Worker("js/my_task.js");
worker.onmessage = function(oEvent):void{
    console.log("Called back by the worker!\n");
};
worker.postMessage("start"); // start the worker.

my_task.js中的代码还是加载一个文件。代码如下:

self.addEventListener('message', function (e) {
    var xmlreq = new XMLHttpRequest();
    xmlreq.responseType = "text";
    xmlreq.onload = function (e) {
        var data = e.currentTarget.response;
        self.postMessage(data);
    }
    xmlreq.open("get","../atlas/comp.atlas");
    xmlreq.send()
}, false);

编译运行代码,可以看到控制台输出了我们加载comp.atlas的数据。

总结:web worker我们一般应用到解析加载大的文件,比如大的json文件,比较费时的计算,或者不需要即时加载的一些资源都可以放到后台线程来完成,这样用户基本感受不到主线程的卡顿。增强项目的流畅性。提高用户体验。

Copyright ©Layabox 2022 all right reserved,powered by LayaAir Engine更新时间: 2024-03-01 11:00:43

results matching ""

    No results matching ""