How to transform Array.forEach to asynchronous with Q.js?

asynchronous, breeze, javascript, q

Solution

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

Problem

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.

Original source