JavaScript Worker:如何在运行昂贵的任务时检查是否收到了消息

时间:2014-05-03 01:57:32

标签: javascript javascript-events worker

我在Worker上运行一个非常昂贵的任务,类似于

for(var i = 0; i < 1000000000; i++)
    //operations using i...

我怎样才能这样做,在那个循环中,我可以检查是否收到了工作者所有者要求它停止的消息?我想有这样的东西

for(var i = 0; i < 1000000000; i++)
    if(windowDidNotAskToStop())
        //operations using i...

现在我已经注册了一个onmessage函数,所以我可以开始收听来自所有者的消息,但是在我的循环运行时它被阻止(显然)。

我认为来自所有者的postMessage调用在某处排队,所以我只需访问它就可以处理来自循环内部的调用。

1 个答案:

答案 0 :(得分:2)

您必须像往常一样处理事件并设置标记,但请务必留出时间让您的循环接收事件,可能使用setTimeout

var exitLoop = false;

(function loop(i) {
    if (exitLoop || i >= 1000000000) {
        return;
    }

    // …

    setTimeout(function () {
        loop(i + 1);
    }, 0);
})(0);

onmessage = function (e) {
    if (e.data === 'stop') {
        exitLoop = true;
    }
};

或者,作为一般效用函数:

function asyncIterateRange(start, end, callback) {
    var exitLoop = false;
    var doneCallbacks = [];

    (function loop(i) {
        if (exitLoop) {
            return;
        }

        if (i >= end) {
            doneCallbacks.forEach(function (callback) {
                callback();
            });

            return;
        }

        callback(function () {
            setTimeout(function () {
                loop(i + 1);
            }, 0);
        });
    })(start);

    return {
        abort: function abort() {
            exitLoop = true;
        },
        done: function addDoneCallback(callback) {
            doneCallbacks.push(callback);
        }
    };
}

像这样使用它:

var innerIterator;
var outerIterator = asyncIterateRange(0, 1000000, function outerLoop(next) {
    innerIterator = asyncIterateRange(0, 1000, function innerLoop(next) {
        // …
        next();
    }).done(next);
});

// To stop:
if (innerIterator) {
    innerIterator.abort();
}

outerIterator.abort();