How to Sequentially Run Promises with Q in JavaScript

How to sequentially run promises with Q in Javascript?

but instead they are being output immediately for some reason.

You are calling them already here:

promiseFuncs.push(getDelayedString(str));
// ^^^^^

You would need to push function(){ return getDelayedString(str); }. Btw, instead of using pushing to an array in an each loop you rather should use map. And actually you don't really need that anyway but can reduce over the strings array directly:

function onceUponATime() {
var strings = ["Once", "upon", "a", "time"];

return strings.reduce(function (soFar, s) {
return soFar.then(function() {
return getDelayedString(s);
});
}, Q());
}

Oh, and don't use document.write.

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.

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

promise .then() to run sequentially inside a for loop

If you want to run these in series then you need to trigger async function n when you know that async function n-1 is finished; i.e. in the then callback. Calling a function recursively is likely to be the easiest way to do this if you've rejected async and await.

function somethingAsync(value) {
return new Promise(res => setTimeout(res, 500, value * value));
}

function processInputInSeries(input) {
function processNext(index, input, results) {
if (index >= input.length) return results;
return somethingAsync(input[index]).then(function (result) {
return processNext(index + 1, input, [...results, result]);
});
}

return processNext(0, input, []);
}

const resultPromise = processInputInSeries([1,2,3]);
resultPromise.then(function(results) { console.log(results) });

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

Nodejs / Q : Chaining promises sequentially

Judging from your example, I would assume that you already saw Sequences part of Q readme, but failed to understand it.

Original example used "waterfall" model, when the output of each function passed as an input to the next one:

var funcs = [foo, bar, baz, qux];

var result = Q(initialVal);
funcs.forEach(function (f) {
result = result.then(f);
});
return result;

But you just want to execute all our functions in sequence, so you could simply bind each function with its variables:

var args = ["first", "second", "third", "fourth"];

var result = Q();
args.forEach(function (t) {
result = result.then(treat.bind(null, t));
});
return result;

In my example treat function will be called 4 times sequentially, and result promise will be resolved with the value of latest treat call (results of all previous calls will be ignored).

The trick is that .then method accepts a handler which will be called after current promise will be resolved and returns a new promise. So, you should pass to .then a function which should be called on the next step of your execution chain. treat.bind(null, t) binds treat function with attribute t. In other words, it returns a new function, which will invoke treat, passing t as its first argument.

Running sequential functions in Q Promise (Node.js)

If you use the chained response, that the value of the first Promise will get passed to the second through the continuation, so your get2 should accept an argument:

var get1 = function () {
var deferred = q.defer();
deferred.resolve('hello world');

return deferred.promise;
};

var get2 = function (result) {
var deferred = q.defer();
deferred.resolve(result + 2);

return deferred.promise;
};

//Then you can use it like so
get1().then(get2).then(console.log.bind(console), console.error.bind(console));

Also as a side note you should avoid using the defer api where possible, since it is considered an anti-pattern.

resolving Promises sequentially

Get weird with Promises

An async queue, a spin-off one of my previous answers; I've added random completion time to simulate a real environment:

class Queue {    constructor() {        this.queue = [];    }
enqueue(obj) { return this.queue.push(obj); }
dequeue() { return this.queue.shift(); }
hasWork() { return (this.queue.length > 0); }}
class AsyncQueue extends Queue { constructor(job) { super(); this.job = job; }
process(cb) { return this.job(this.dequeue()).then(data => { cb(data); if (this.hasWork()) return this.process(cb); }); }}
//MUST RETURN Promisefunction work() { var duration = chooseDelay(); console.log('START JOB, I.E., MAKE REQUEST (will take %s)', duration); return t_o(duration);}
function report() { console.log('JOB DONE');}
function done() { console.log('ALL WORK DONE');}
function t_o(delay) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(); }, delay); });}
function chooseDelay() { var delays = [200, 1000, 4000, 100, 50, 7000]; return delays[parseInt(Math.random() * 100) % delays.length];}
var q = new AsyncQueue(work);
for (var packet = 0; packet < 10; ++packet) q.enqueue(packet);
q.process(report).then(done);


Related Topics



Leave a reply



Submit