How to Execute Array of Promises in Sequential Order

How to execute promises sequentially, passing the parameters from an array?

You can make the repeated application of .then into a fold pretty neatly if you’re okay with creating as many promises as array elements as is the case in the question:

myArray.reduce(
(p, x) =>
p.then(() => myPromise(x)),
Promise.resolve()
)

but given support, an async function is a better choice. It’s nicely readable and has O(1) instead of O(n) memory overhead.

const forEachSeries = async (iterable, action) => {
for (const x of iterable) {
await action(x)
}
}

forEachSeries(myArray, myPromise)

If you want to collect the return values as an array, that’s:

const mapSeries = async (iterable, fn) => {
const results = []

for (const x of iterable) {
results.push(await fn(x))
}

return results
}

or, without async function support,

const mapSeries = (iterable, fn) => {
const iterator = iterable[Symbol.iterator]()
const results = []
const go = () => {
const {value, done} = iterator.next()

if (done) {
return results
}

return fn(value).then(mapped => {
results.push(mapped)
return go()
})
}

return Promise.resolve().then(go)
}

Runnable snippet:

const myArray = [1, 2, 3, 4, 5, 6]

const sleep = ms =>
new Promise(res => {
setTimeout(res, ms)
})

const myPromise = num =>
sleep(500).then(() => {
console.log('done: ' + num)
})

const forEachSeries = async (iterable, action) => {
for (const x of iterable) {
await action(x)
}
}

forEachSeries(myArray, myPromise)
.then(() => {
console.log('all done!')
})

Execute an Array of promises sequentially without using async/await

Here could be a possible option:

let p = Promise.resolve([]);
promisesArray.forEach(q => {
p = p.then(responses => {
//based on the nature of each q, to start execution
//use either q().then() or q.then()
return q().then(response => {
//Any further logic can be here.
console.log(response);
return responses.concat([response]);
})
})
})

p.then(responses => {
// here you have all of the responses.
})

How can I execute array of promises in sequential order?

If you already have them in an array then they are already executing. If you have a promise then it's already executing. This is not a concern of promises (I.E they are not like C# Tasks in that regard with .Start() method). .all doesn't execute anything
it just returns a promise.

If you have an array of promise returning functions:

var tasks = [fn1, fn2, fn3...];

tasks.reduce(function(cur, next) {
return cur.then(next);
}, RSVP.resolve()).then(function() {
//all executed
});

Or values:

var idsToDelete = [1,2,3];

idsToDelete.reduce(function(cur, next) {
return cur.then(function() {
return http.post("/delete.php?id=" + next);
});
}, RSVP.resolve()).then(function() {
//all executed
});

JavaScript Promises: Executing Promises Sequentially

The executeSequentially method returns all the Promises one after each other. It happens to iterate over promiseFactory, but it could be written as:

function executeSequentially(promiseFactories) {
return doFirstThing()
.then(() => doSecondThing())
.then(doThirdThing() );
}

It is just the same. We are basically returning a Promise.

Now, however, we want to iterate over a collection of promises.

When iterating, we need to attach the current Promise to the previous with a then. But the forEach does not expose the next Promise -or the previous- in every iteration. And yet we still need it in order to keep chaining Promises one by one. Hence, the result 'hack':

function executeSequentially(promiseFactories) {
var result = Promise.resolve(); /*We need a thing that keeps yelling
the previous promise in every iteration, so we can keep chaining.
This 'result' var is that thing. This is keeping a Promise in every
iteration that resolves when all the previous promises resolve
sequentially. Since we don't have a Promise in the array
previous to the first one, we fabricate one out of 'thin air'
with Promise.resolve() */
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory); /* Here result is update
with a new Promise, with is the result of chaining `result`
with the current one. Since `result` already had all the previous ones,
at the end, `result` will be a Promise that depends upon all the
Promises resolution.*/
});
return result;
}

Now, there's also a syntax quirk that maybe is puzzling you:

result = result.then(promiseFactory);

This line is pretty much the same as the following:

result = result.then(resolvedValue => promiseFactory(resolvedValue));

Please if somebody can help me understand how calling the promiseFactory method inside the 'then' method of the empty promise makes it execute sequentially, like so. Or is it because of the forEach loop ?

First thing first, promiseFactory is a pretty bad name there. The method should be better written as follows:

function executeSequentially(promises) {
var result = Promise.resolve(); // this is the most problematic line
promises.forEach(function (currentPromise) {
result = result.then(currentPromise);// what is happening here ?
});
return result;
}

So:

how calling the currentPromise method inside the 'then' method of the empty promise makes it execute sequentially?

It makes execute sequentially because when you attach a Promise to another by then, it executes sequentially. Is a then thing, it is not at all related to the fact that we are iterating over Promises. With plain Promises outside an iteration it works pretty much the same:

Promise.resolve() // fake Promises that resolves instanly
.then(fetchUsersFromDatabase) // a function that returns a Promise and takes
// like 1 second. It won't be called until the first one resolves
.then(processUsersData) // another function that takes input from the first, and
// do a lot of complex and asynchronous computations with data from the previous promise.
// it won't be called until `fetchUsersFromDatabase()` resolves, that's what
// `then()` does.
.then(sendDataToClient); // another function that will never be called until
// `processUsersData()` resolves

Resolve promises one after another (i.e. in sequence)?

Update 2017: I would use an async function if the environment supports it:

async function readFiles(files) {
for(const file of files) {
await readFile(file);
}
};

If you'd like, you can defer reading the files until you need them using an async generator (if your environment supports it):

async function* readFiles(files) {
for(const file of files) {
yield await readFile(file);
}
};

Update: In second thought - I might use a for loop instead:

var readFiles = function(files) {
var p = Promise.resolve(); // Q() in q

files.forEach(file =>
p = p.then(() => readFile(file));
);
return p;
};

Or more compactly, with reduce:

var readFiles = function(files) {
return files.reduce((p, file) => {
return p.then(() => readFile(file));
}, Promise.resolve()); // initial
};

In other promise libraries (like when and Bluebird) you have utility methods for this.

For example, Bluebird would be:

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));

var readAll = Promise.resolve(files).map(fs.readFileAsync,{concurrency: 1 });
// if the order matters, you can use Promise.each instead and omit concurrency param

readAll.then(function(allFileContents){
// do stuff to read files.
});

Although there is really no reason not to use async await today.

How to execute promises in order and return all results

Try using an async function and iterating over the promises in a for...of loop:

Resolve promises one after another (i.e. in sequence)?

Execute promises map sequentially

The problem with your current code is that Promise.prototype.map, like forEach, does not wait for asynchronous functions called inside it to complete. (No asynchronous call will ever be waited for unless you tell the interpreter to do so explicitly with await or .then)

Have t1 await each call of t2:

async function t1(){
let arr1 = [1,2,3,4,5];
const results = [];
for (const val of arr1) {
results.push(await t2(val));
}
return results;
}

Or if you want to use reduce instead of async/await:

const delay = () => new Promise(res => setTimeout(res, 500));function t1(){  let arr1 = [1,2,3,4,5];  return arr1.reduce((lastProm, val) => lastProm.then(    (resultArrSoFar) => t2(val)      .then(result => [...resultArrSoFar, result])  ), Promise.resolve([]));}
function t2(event){ return delay().then(() => { console.log('iter'); return event; });}
t1() .then(results => console.log('end t1', results));

Sequential execution of Promise.all

the Promises unfortunatelly does not allow any control of their flow. It means -> once you create new Promise, it will be doing its asynchronous parts as they like.

The Promise.all does not change it, its only purpose is that it checks all promises that you put into it and it is resolved once all of them are finished (or one of them fail).

To be able to create and control asynchronous flow, the easiest way is to wrap the creation of Promise into function and create some kind of factory method. Then instead of creating all promises upfront, you just create only one promise when you need it, wait until it is resolved and after it continue in same behaviour.

async function doAllSequentually(fnPromiseArr) {  for (let i=0; i < fnPromiseArr.length; i++) {    const val = await fnPromiseArr[i]();    console.log(val);  }}
function createFnPromise(val) { return () => new Promise(resolve => resolve(val));}
const arr = [];for (let j=0; j < 10; j++) { arr.push(createFnPromise(Math.random()));}
doAllSequentually(arr).then(() => console.log('finished'));


Related Topics



Leave a reply



Submit