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
Access JavaScript Nested Objects Safely
How to Detect If Flash Is Installed and If Not, Display a Hidden Div That Informs the User
Javascript/Jquery: Test If Window Has Focus
Closure in JavaScript - Whats Wrong
Why Use Jquery On() Instead of Click()
Scrolltop Animation Without Jquery
How to Swipe Top Down Jquery Mobile
How to Resolve Iframe Cross Domain Issue
Scroll to Element on Click in Angular 4
Screen Scraping from a Web Page with a Lot of JavaScript
Angular2/Spring Boot Allow Cross Origin on Put
How to Find the Array Index with a Value
Intercepting Call to the Back Button in My Ajax Application
Difference Between the 'Controller', 'Link' and 'Compile' Functions When Defining a Directive
Internet Explorer 11 Detection
How to Resize Twitter Bootstrap Modal Dynamically Based on the Content