最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to transform Array.forEach to asynchronous with Q.js? - Stack Overflow

programmeradmin2浏览0评论

I need to execute dynamically a function for all items of an array, but Array.forEach execute in sequence and I need execute in asynchronous.

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

I try this:

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.
});

But the execution is always in sequence and I need the execution in parallel.

The doSomething(item) method:

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
        });
    }

Please help me.

I need to execute dynamically a function for all items of an array, but Array.forEach execute in sequence and I need execute in asynchronous.

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

I try this:

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.
});

But the execution is always in sequence and I need the execution in parallel.

The doSomething(item) method:

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
        });
    }

Please help me.

Share Improve this question edited Feb 12, 2014 at 19:47 kuskunko asked Feb 12, 2014 at 14:43 kuskunkokuskunko 3306 silver badges17 bronze badges 6
  • Look up WebWorkers, javascript is single-threaded. – OneOfOne Commented Feb 12, 2014 at 14:47
  • you can put items.forEach in setTimeout. setTimeout(function () {(your code goes here)}, 1) – Damian Krawczyk Commented Feb 12, 2014 at 14:49
  • You're trying to use the wrong tool for the job. Promises are not a tool to convert synchronous code into asynchronous code. They are a means of taming the complexity of asynchronous callback chains. – Scott Sauyet Commented Feb 12, 2014 at 14:52
  • This isnt code review but this is a good place for map var promises = items.map(function() {/*create promise*/ return promise;}); – megawac Commented Feb 12, 2014 at 15:27
  • 1 Can you clarify what you mean by “asynchronous”? “asynchronous” implies that doSomething will not be finished in one event. If it does finish in one event, it will always be executed in “serial”, but not necessarily in order. If doSomething returns a promise, or has a callback, and won’t finish in a single event, that opens up the possibility of “parallel”, where multiple jobs will have events that are interleaved. Either way, I can provide tips. – Kris Kowal Commented Feb 12, 2014 at 17:29
 |  Show 1 more comment

2 Answers 2

Reset to default 21

This answer assumes that doSomething is itself an asynchronous operation. This means that it will have to yield to the event loop and wait for another event at least once in a while. If doSomething is synchronous, there is no benefit to composing it asynchronously.

Within the realm of composite asynchronous jobs, there are serial and parallel variations. The serial model causes job(n + 1) to begin only after job(n) finishes. The parallel model starts all jobs initially and finishes when all jobs are finished. In both of these regards, I can give you tips.

In parallel, you can use Array map and Q.all, assuming doSomething accepts a value from jobs and returns a promise:

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

To do jobs in serial order, use Array reduce.

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

If you want to perform jobs in serial, but only proceed to the next job depending on the result of the first, you can use reduceRight to compose a function.

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");
})();

If you have an array that contains functions that need to be executed in order, feeding the output of the previous into the input of the next, you can use reduce even more succinctly.

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

The tutorial in Q’s readme covers more cases and I am told has been helpful https://github.com/kriskowal/q#tutorial

It appears as though you are executing the promise you are creating immediately during iteration as you push it to the array. Try changing...

promises.push(promise());

To...

promises.push(promise);
发布评论

评论列表(0)

  1. 暂无评论