阻止'加入' html5 webworker上的方法

时间:2016-09-28 08:35:10

标签: javascript html5 multithreading web-worker

我在js中实现了类似于.net / c#:

中的Thread类的Thread类



function Thread(func) {
    var o = this;
    o.func = func;
}

Thread.prototype.Start = function (p, cb) {
    var o = this;

    var toClass = {}.toString;
    var wcode = "" + o.func;
    var re = /\((.*?)\)/;
    var rearr = re.exec(wcode)[1].split(",");
    var odta = {};
    var tobj = [];
    var pstr = "";
    for (var i = rearr.length - 1; i >= 0; i--)
    {
        odta[rearr[i]] = p ? p[i] : p;
        pstr += rearr[i] + "=" + rearr[0] + ".data." + rearr[i] + ";";
        if (p && p[i] && (toClass.call(p[i]) == "[object ArrayBuffer]")) {
          //  tobj[tobj.length] = p;
          //  trace("added arraybuffer");
        }
    }

    wcode = wcode.replace("{", "{" + pstr);
    re = /return ([^;\}]*?)([;\}])/g;
    wcode = wcode.replace(re, "postMessage($1)$2");
    //trace("re:" + wcode);
    var blob = new Blob(["onmessage = " + wcode ]);
    // Obtain a blob URL reference to our worker 'file'.
    var blobURL = window.URL.createObjectURL(blob);
    var worker = new Worker(blobURL);
    worker.onmessage = function (e) {
        trace("callback from worker " + e.data);
        if (cb)
            cb(e.data);
    };
    worker.postMessage(odta, tobj);


};




现在我想实施“加入”#39;方法,即等待网络工作者完成(或发送表明已完成的消息)。我知道我可以使用计时器,但这不会保留打电话的上下文,关闭也不是我想要的,它可能是一个真实的'阻止电话。

它适用于Chrome& FF(我已经放弃了IE)。

有没有办法像.net的join-method那样进行这样的阻止调用?

3 个答案:

答案 0 :(得分:0)

您可以使用Promise构造函数Promise.all()

function handleWorker(/* args */) {
  return new Promise((resolve, reject) => {
    // create worker, do stuff
    worker.onmessage = function(e) {
      resolve(/* optionally pass a value */)
    }
    worker.onerror = function(err) {
      reject(err)
    }
  })
}

var workers = [];

for (var i = 0; i < 4; i++) { 
  workers.push(handleWorkers(/* arg */))
}

Promise.all(workers)
.then(res => console.log("all workers have posted message", res));
// handle error
.catch(function(workerError) {
  console.log(workerError)
});

jsfiddle https://jsfiddle.net/yo8r3fzw/

答案 1 :(得分:0)

由于我一直在开发支持并发编程的多线程JS API(OODK-JS),我可以直截了当地回答:

无法阻止线程等待来自另一个线程的信号。

为什么呢?

因为webworkers通过消息交换与主线程通信。一个好的尝试是在主线程中实现一个无限循环,并将一个变量设置为stop条件,当主线程收到来自webworker的消息以打破循环时,该变量将被更新。不幸的是,由于主线程是循环的,因此在循环完成之前不会收到来自webworkers的消息,因为它是主线程保持循环不确定。

解决方案?

阻止主线程是不可能的,但是当每个webworker发送消息'task.done'时,当所有webwokers完成作业时,仍然可以通过实现计数器递增来触发动作。一旦计数器达到初始化的webworkers数量,就可以触发一个动作

答案 2 :(得分:0)

我已经尝试过guest271314的建议,但还没有,希望静态Promise.resolve会阻止,因为文档说它返回一个“已解决”的承诺。这是我到目前为止所做的:

function Thread(func) {
    var o = this;
    o.func = func;
}

Thread.prototype.Start = function (p, cb) {
    var o = this;

    var toClass = {}.toString;
    var wcode = "" + o.func;
    trace(wcode);
    var re = /\((.*?)\)/;
    var rearr = re.exec(wcode)[1].split(",");
    var odta = {};
    var tobj = [];
    var pstr = "";
    for (var i = rearr.length - 1; i >= 0; i--)
    {
        odta[rearr[i]] = p ? p[i] : p;
        pstr += rearr[i] + "=" + rearr[0] + ".data." + rearr[i] + ";";
        if (p && p[i] && (toClass.call(p[i]) == "[object ArrayBuffer]")) {
            tobj[tobj.length] = p[i];
            //  trace("added arraybuffer");
        }
    }

    wcode = wcode.replace("{", "{" + pstr);
    re = /return ([^;\}]*?)([;\}])/g;
    wcode = wcode.replace(re, "postMessage($1);return;$2");
    //trace("re:" + wcode);
    var blob = new Blob(["onmessage = " + wcode ]);
    // Obtain a blob URL reference to our worker 'file'.
    var blobURL = window.URL.createObjectURL(blob);
    var worker = new Worker(blobURL);

    o.promise = new Promise(function(resolve, reject) {
        worker.onmessage = function (e) {
            trace("callback from worker " + e.data);
            if (cb)
                cb(e.data);
            resolve();
        };
    });
    worker.postMessage(odta, tobj);
};

Thread.prototype.Join = function () {
    var o = this;
    Promise.resolve(o.promise);
    // I'd like to get here AFTER the worker has finished
};

用以下方法测试:

 var t = new Thread(myfunction);
 t.Start([1, 2, 3, new ArrayBuffer(2)]);
 t.Join();
 trace("Thread done!");