I have seen Chaining an arbitrary number of promises in Q ; my question is different.
How can I make a variable number of calls, each of which returns asynchronously, in order?
The scenario is a set of HTTP requests, the number and type of which is determined by the results of the first HTTP request.
I'd like to do this simply.
I have also seen this answer which suggests something like this:
var q = require('q'), itemsToProcess = ["one", "two", "three", "four", "five"]; function getDeferredResult(prevResult) { return (function (someResult) { var deferred = q.defer(); // any async function (setTimeout for now will do, $.ajax() later) setTimeout(function () { var nextResult = (someResult || "Initial_Blank_Value ") + ".." + itemsToProcess[0]; itemsToProcess = itemsToProcess.splice(1); console.log("tick", nextResult, "Array:", itemsToProcess); deferred.resolve(nextResult); }, 600); return deferred.promise; }(prevResult)); } var chain = q.resolve("start"); for (var i = itemsToProcess.length; i > 0; i--) { chain = chain.then(getDeferredResult); }
...but it seems awkward to loop through the itemsToProcess in that way. Or to define a new function called "loop" that abstracts the recursion. What's a better way?
Promise chaining: Promise chaining is a syntax that allows you to chain together multiple asynchronous tasks in a specific order. This is great for complex code where one asynchronous task needs to be performed after the completion of a different asynchronous task.
Yes, the values in results are in the same order as the promises .
Introduction to the JavaScript promise chainingThe callback passed to the then() method executes once the promise is resolved. In the callback, we show the result of the promise and return a new value multiplied by two ( result*2 ).
all itself as a promise will get resolved once all the ten promises get resolved or any of the ten promises get rejected with an error.
There's a nice clean way to to this with [].reduce
.
var chain = itemsToProcess.reduce(function (previous, item) { return previous.then(function (previousValue) { // do what you want with previous value // return your async operation return Q.delay(100); }) }, Q.resolve(/* set the first "previousValue" here */)); chain.then(function (lastResult) { // ... });
reduce
iterates through the array, passing in the returned value of the previous iteration. In this case you're returning promises, and so each time you are chaining a then
. You provide an initial promise (as you did with q.resolve("start")
) to kick things off.
At first it can take a while to wrap your head around what's going on here but if you take a moment to work through it then it's an easy pattern to use anywhere, without having to set up any machinery.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With