Web Worker 可以做什么

• 加密/解密长字符串
• 复杂的数学运算(例如:质数运算,加密,模拟退火算法等)
• 存储大数组
• 网络请求以及响应数据处理
• local storage上的计算和数据处理
• 提前获取或者缓存数据
• 代码语法高亮或者其他的实时文本分析(例如:拼写检查)
• 图片处理
• 分析/处理视频音频(包含面部和声音识别)
• 后台I/O
• 轮训web service
• 处理大数组或者大量的JSON响应

Web Workers 不能访问DOM的父页面,所以它不能访问下面的对象:
• window对象
• document对象
• parent对象
• 最后但是同样重要的,它不能访问依赖于上述对象的javascript库,例如jQuery

因为Web Workers的多线程特性,它只能访问有限的javascript功能。下面是它能使用的功能:
• navigator对象
• location对象 (只读)
• XMLHttpRequest函数
• 用来转换Base64 与二进制数据的atob()和dtoa()函数
• setTimeout() / clearTimeout() and setInterval() / clearInterval()
• dump()
• The application cache
• 使用importScripts()导入的脚本
• Spawning other Web Workers

Worker 的执行
•对于需要在后台长时间运行的任务,Web Workers 注册一个基于消息事件的处理者,这个Web Worker不会退出,它会保持监听新的消息。
•对于需要从web引用偏离出来的单独任务,像获取和分析大规模 JSON对象,Web Workers 不会注册基于消息事件的处理者。任务一旦执行完成Web Worker就会退出。

使用Web Worker

用例一:
UI页面输入一个整数,web worker 计算平方,并将结果发送到UI
doworker.js代码

//响应UI线程事件
self.onmessage=function(event){
     //返回信息给UI线程
     self.postMessage(event.data*event.data);
}

html代码

<!DOCTYPE html>
<html>
     <head>
          <title>a demo for worker</title>
          <script type="text/javascript" src="modernizr.custom.js"></script>
          <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
          <script type="text/javascript">
               //用Modernizr插件检测浏览器是否支持webworker功能
               if(Modernizr.webworkers){
                    console.log('support for web workers!')
               }
               //创建Worker对象,这里的doworker.js是要另起线程执行的任务
               var worker=new Worker("doworker.js");
               //注册事件,可以接收doworker.js线程发送的数据
               worker.addEventListener('message',function(e){
                    $('<div>'+e.data+'</div>').appendTo('#show')
               },false);
              
               function sendMessage(){
                    var txt=document.getElementById('txt_1');
                    //UI线程给doworker.js线程发送数据
                    worker.postMessage(txt.value);
               }
          </script>
     </head>
     <body>
          <input type="text" id="txt_1"/>
          <input type="button" id="bt_1" value="send message" onclick="javascript:sendMessage();"/>
          <div id='show'></div>
     </body>
</html>

加载外部脚本

要加载额外的脚文件或者库到Web Worker里面,使用全局的importScripts()函数。这个函数接收一个表示要导入资源的字符串作为参数。如果你输入空的参数,什么都不会导入。如果你输入一个或者多个URL(或者文件名),它将加载并且在Web Worker中执行脚本(不管MIME类型)

下面的代码加载script1.js和script2.js到Worker:
importScripts(‘script1.js’);
importScripts(‘script2.js’);
也可以这么写:
importScripts(‘script1.js’, ‘script2.js’);
浏览器可能以任意的顺序获取脚本,如果出错则会返回一个NetworkError异常。在所有脚本获取完成以后,脚本将按照参数的顺序执行。这些脚本将被同步处理,直到所有脚本都获取和处理完成,importScript()函数才会返回。

用例二:
UI界面显示start和stop按钮,控制web worker启动和停止worker。worker负责用ajax请求(XMLHttpRequest),从服务器获取信息,然后发送给UI页面显示。
注意:本用例也体现了UI控制web worker的一种模式,通过worker里面switch对于UI传递命令的判断,来实现UI控制worker。

UI页面javascript代码

var workerAjax;

function start() {
    workerAjax = new Worker("Scripts/MyJs/task_ajax.js");
    workerAjax.addEventListener("message", function (e) { addMsg(e.data); }, false);
    workerAjax.postMessage({ 'cmd': 'start', 'msg': 'worker_ajax开始...' });
}

function stop() {
    if (workerAjax) {
        workerAjax.postMessage({ 'cmd': 'stop', 'msg': 'worker_ajax停止' });
    }
}

web worker(task_ajax.js)代码

var xmlHttpRequest = new XMLHttpRequest();
var url = "/home/WorkerRequestAjax?user=Tom";

function sendRequest() {
    xmlHttpRequest.open("get", url, false);
    xmlHttpRequest.send(null);
    if (xmlHttpRequest.status == 200) {
        postMessage(xmlHttpRequest.responseText);
        setTimeout(sendRequest, 3000);
    }
}

self.addEventListener('message', function (e) {
    var data = e.data;
    switch (data.cmd) {
        case 'start':
            self.postMessage('WORKER STARTED: ' + data.msg);
            sendRequest();
            break;
        case 'stop':
            self.postMessage('WORKER STOPPED: ' + data.msg + '. (buttons will no longer work)');
            self.close(); // Terminates the worker.
            break;
        default:
            self.postMessage('Unknown command: ' + data.msg);
    };
}, false);

用例三:
本用例在全局函数importScripts的使用基础上,结合服务器,实现web worker可以指定callback。

UI页面javascript代码

function workerImprotScripts() {
    if (Modernizr.webworkers) {
        var worker = new Worker("Scripts/MyJs/task_Polling.js");
        worker.addEventListener("message", function(e) {
            addMsg(e.data);
        }, false);

        worker.onerror = function(e) {
            var errorMsg = e.message + " (" + e.filename + ":" + e.lineno + ")";
            addMsg(errorMsg);
            throw new Error(errorMsg);
        };
    }
}

web worker(task_Polling.js)代码

var connections = 0;
var updateDelay = 5000;

function getURL() {
    return 'http://localhost:7541/Home/ReturnMessageForWorker?user=Somebody' +'&callback=processMsg';
    //return 'http://localhost:7541/Scripts/MyJs/importStripts_1.js?callback=processMsg';
}

function getMsg() {
    try {
        var url = getURL();
        postMessage("开始获取信息...");
        importScripts(url);
        postMessage("获取信息完毕...");
    } catch(e) {
        postMessage("发生错误" + e.message );
        setTimeout(getMsg, updateDelay);
    }
}

function processMsg(data) {
    var str = data.length;
    if (str > 0) {
        postMessage("有新信息:" + data);
    }
    setTimeout(getMsg, updateDelay);
}

//第一次执行worker
getMsg();

注意用例三,服务器端返回已js文件(当然,也可以直接返回js文件,不过这样就失去了服务器动态控制),下面是服务器段返回给importScripts()调用的js文件的方法,worker在加载完所有js文件后,会按照importScripts()参数顺序,逐个执行这些js文件。

/// <summary>
/// 根据web worker提供的查询参数,计算数据,将此数据和回调函数替换到importStripts_1.js文件,然后返回此文件,
/// web worker 的importScripts()函数接到这个js文件后,就会执行。这样就实现了根据web worker提供的参数,
/// 动态动态调用web worker里面的js函数
/// </summary>
/// <param name="user">查询参数</param>
/// <param name="callback">web worker 通过 improtScripts()可以指定回调函数</param>
/// <returns></returns>
public FileResult ReturnMessageForWorker(string user,string callback)
{
    var st = new StreamReader(Server.MapPath("~/Scripts/MyJs/importStripts_1.js"));
    string js = st.ReadToEnd();
    js=js.Replace("_callback", callback).Replace("_data", user);
    byte[] bytes=Encoding.UTF8.GetBytes(js);

    return File(bytes, "application/x-javascript", "importStripts_1.js");
}

1 对 “web workers的使用”的想法;

发表评论

电子邮件地址不会被公开。 必填项已用*标注