如何将Array.forEach转换为与Q.js异步?

时间:2014-02-12 14:43:50

标签: javascript asynchronous breeze q

我需要为数组的所有项动态执行函数,但是Array.forEach按顺序执行,我需要异步执行。

items.forEach(function(item) {
    doSomething(item);
});

我试试这个:

var promises = [];

items.forEach(function(item) {
    var promise = function() {
        return Q.fcall(function() {
            doSomething(item);
        });
    };
    promises.push(promise());
});

Q.all(promises).then(function () {
    otherFunction(datacontext.mainList); //use datacontext.mainList filled.
});

但执行总是按顺序执行,我需要并行执行。

doSomething(item)方法:

function doSomething(item) {
        var children = getChildren(item); //get data from local with manager.executeQueryLocally
        var total = getTotal(children); //simple calculations
        datacontext.mainList.push({
            name: item.firstName() + ' ' + item.lastName(),
            total: total
        });
    }

请帮帮我。

2 个答案:

答案 0 :(得分:21)

这个答案假定doSomething本身就是一个异步操作。这意味着它必须屈服于事件循环并且偶尔等待另一个事件至少一次。如果doSomething是同步的,则异步编写它是没有好处的。

在复合异步作业领域,存在串行和并行变体。串行模型导致作业(n + 1)仅在作业(n)结束后开始。并行模型最初启动所有作业,并在所有作业完成后结束。在这两方面,我都可以给你提示。

同时,您可以使用Array map和Q.all,假设doSomething接受来自jobs的值并返回一个承诺:

return Q.all(jobs.map(doSomething))

要按顺序执行作业,请使用Array reduce。

return jobs.reduce(function (previous, job) {
    return previous.then(function () {
        return doSomething(job);
    });
}, Q());

如果您想以序列方式执行作业,但只根据第一个作业的结果继续下一个作业,您可以使用reduceRight来组成一个函数。

return jobs.reduceRight(function (next, job) {
    return function (previous) {
        return doSomething(job).then(function (result) {
            if (result.isGood(previous)) return result;
            return next(result);
        });
    });
}, function fallthrough(previous) {
    throw new Error("No result was satisfactory");
})();

如果你有一个包含需要按顺序执行的函数的数组,将前一个的输出输入到下一个的输入中,你可以更简洁地使用reduce

return functions.reduce(Q.when, Q());

Q自述文件中的教程涵盖了更多案例,我被告知有帮助https://github.com/kriskowal/q#tutorial

答案 1 :(得分:0)

当您将其推送到阵列时,似乎您正在执行迭代期间立即创建的承诺。尝试改变......

promises.push(promise());

要...

promises.push(promise);