How can I perform dynamic chaining in Javascript Promises, all the time I have seen only hardcoding of the calls for eg., (promise).then(request/functionName).then(request/functionName)
-
Dynamic - where are they coming from? What's the problem you're trying to solve? Of course you can pass whatever callbacks you like, however chosen, not only hardcoded function expressions. – Bergi Jun 15 '15 at 20:44
-
Thanks Bergi for the reply, they are coming from user actions/events such as button clicks etc., – R Ajay Jun 15 '15 at 20:50
-
You mean like `var promise = …; button.onclick = function(e) { promise.then(doSomething); };`? Surely you can do that, yes. Have you tried it? – Bergi Jun 15 '15 at 20:52
-
Yes In the same way..I ran out of Ideas Bergi...... – R Ajay Jun 15 '15 at 21:05
-
So what is the result that you want to get? Do you already have code that does not work or looks too complicated? – Bergi Jun 15 '15 at 21:16
-
@Bergi don't we have like.. 10 duplciates for this? – Benjamin Gruenbaum Jun 15 '15 at 22:03
-
Also WooHoo 3000 promise questions. Get that badge already :P – Benjamin Gruenbaum Jun 15 '15 at 22:03
-
@BenjaminGruenbaum: probably. I'm just still trying to figure out what the OP actually wants. – Bergi Jun 15 '15 at 22:26
10 Answers
Given an array functions that all return promises, you can use reduce()
to run them sequentially:
var myAsyncFuncs = [
function (val) {return Promise.resolve(val + 1);},
function (val) {return Promise.resolve(val + 2);},
function (val) {return Promise.resolve(val + 3);},
];
myAsyncFuncs.reduce(function (prev, curr) {
return prev.then(curr);
}, Promise.resolve(1))
.then(function (result) {
console.log('RESULT is ' + result); // prints "RESULT is 7"
});
The example above uses ES6 Promises but all promise libraries have similar features.
Also, creating the array of promise returning functions is usually a good candidate for using map()
. For example:
myNewOrmModels.map(function (model) {
return model.save.bind(model);
}).reduce(function (prev, curr) {
return prev.then(curr);
}, Promise.resolve())
.then(function (result) {
console.log('DONE saving');
});

- 1,629
- 15
- 12
-
-
-
@Салман You can do the same thing reduce does in a `for` loop. Create a variable containing a promise (e.g. `var myPromise = Promise.resolve()`) then loop through your array of functions and **re-set your promise variable** with the each step (e.g. `myPromise = myPromise.then(...)`). If you don't reset your promise variable, all your async functions will be run in parallel, not in step. – MynockSpit Mar 22 '18 at 05:13
-
Sorry I wasn't clear then. I meant memory wastage due to creation of so many promises. For example I have 100 things to do in sequence and I do reduce/for and chain 100 promises. I create 100 promises and consume all that memory. If say my 2nd promise rejects, none further will be useful and the control goes to catch directly. That's what I mean when I say optimising memory usage. I'm wondering if we can only create promise what we want to execute next. – Salman Mar 22 '18 at 06:08
-
-
If I use code like this, I get eslint warnings "*Avoid nesting promises promise/no-nesting*". Is this inevitable? – Duncan Jones Jul 24 '18 at 18:12
-
For the sake of showing they run sequentially, the above might be changed to have different mathematical operations other than +. – Tyler Chong Jun 20 '19 at 21:25
One option is to utilize the properties of objects and the ability to invoke them via strings.
I wrote a small sample Here and posted it below.
The idea is that you have the set of functions that you wish to run set in some namespace or object, as I did in 'myNamespace':
myNamespace = {
"A": function() {return "A Function";},
"B": function() {return "B Function";},
"C": function() {return "C Function";}
}
Then your main promise would run and somehow (via inputs, ajax, prompts, etc.) you would get the string value of the function you want to have run, which isn't known until runtime:
My main promise uses a prompt to get a letter from the user:
var answer = prompt('Starting. Please pick a letter: A,B,C');
if(myNamespace[answer] === undefined)
{
alert("Invalid choice!");
reject("Invalid choice of: " + answer);
}
else
{
resolve(answer);
}
In the next 'then' I use that value (passed via the resolve function) to invoke the function:
.then(function(response) {
funcToRun = myNamespace[response]();})
Finally, I output to html the result of my dynamic function call and I use some recursive fun to make it more interactive and demonstrate that it is dynamic:
.then(function(){
document.getElementById('result').innerHTML = funcToRun;})
.then(function(){
if(prompt("Run Again? (YES/NO)")==="YES")
{
doWork();
}
});
myNamespace = {
"A": function() {return "A Function";},
"B": function() {return "B Function";},
"C": function() {return "C Function";}
}
function doWork()
{
var funcToRun;
new Promise(function(resolve,reject) {
var answer = prompt('Starting. Please pick a letter: A,B,C');
if(myNamespace[answer] === undefined)
{
alert("Invalid choice!");
reject("Invalid choice of: " + answer);
}
else
{
resolve(answer);
}
})
.then(function(response) {
funcToRun = myNamespace[response]();})
.then(function(){
document.getElementById('result').innerHTML = funcToRun;})
.then(function(){
if(prompt("Run Again? (YES/NO)")==="YES")
{
doWork();
}
});
}
doWork();
<div id="result"></div>

- 2,303
- 2
- 21
- 37
-
-
Hi Jason....Quick Question....I will get many requests(fns to be called) from the user actions, How can I check the current promise status and then chain if it is still pending or just run directly if the status is resolved – R Ajay Jun 29 '15 at 17:55
-
@RamuAjay so, there is a Promise state value, but it is private. My guess is to use a `.done(function() {isPromiseDone = true;})` or some external variable to hold the current promise state. As for adding additional "thens" you could hold an array of functions and in the `.done()` function you could check that array and append more "thens" to the promise... that is just a guess though. – JasonWilczak Jun 30 '15 at 12:38
Since promises unwrap, just continue to add then
statements and it will continue to be chained together
function asyncSeries(fns) {
return fns.reduce(function(p, fn) {
return p.then(fn);
}, Promise.resolve());
}
Recursively is a pretty cool way to do it as well :)
function countTo(n, sleepTime) {
return _count(1);
function _count(current) {
if (current > n) {
return Promise.resolve();
}
return new Promise(function(resolve, reject) {
console.info(current);
setTimeout(function() {
resolve(_count(current + 1));
}, sleepTime);
});
}
}

- 2,867
- 22
- 23
-
Hi Travis....Quick Question....I will get many requests(fns to be called) from the user actions, How can I check the current promise status and then chain to it if it is still pending or just run next function directly if the promise state is settled (resolved or rejected) – – R Ajay Jun 30 '15 at 11:43
-
You wrapping the recursive call to the function in a resolve() is what finally got the code I'd been struggling with to work. Thanks so much for the recursive version. – kevinmicke Jan 27 '19 at 03:48
This is ES7 way.
Let's say you have multiple promises defined in an array.
var funcs = [
_ => new Promise(res => setTimeout(_ => res("1"), 1000)),
_ => new Promise(res => setTimeout(_ => res("2"), 1000))
}
And you want to call like this.
chainPromises(funcs).then(result => console.log(result));
You can use async
and await
for this purpose.
async function chainPromises(promises) {
for (let promise of promises) { // must be for (.. of ..)
await promise();
}
}
This will execute the given functions sequentially(one by one), not in parallel. The parameter promises
is an array of functions, which return Promise
.

- 27,270
- 18
- 89
- 122
-
-
This worked very well and I expanded on it a little: https://stackoverflow.com/a/73466109/726127 – Brad Aug 24 '22 at 00:04
I think the simplest way is:
const executePromises = function(listOfProviders){
const p = Promise.resolve(null);
for(let i = 0; i < listOfProviders.length; i++){
p = p.then(v => listOfProviders[i]());
}
return p;
};
I believe the above is basically equivalent to:
const executePromises = async function(listOfProviders) {
for(let i = 0; i < listOfProviders.length; i++){
await listOfProviders[i]();
}
};

- 90,741
- 139
- 482
- 817
This solution based on usage promises of introduced in the EcmaScript 6 (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise), so before use it see table browser`s support https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Browser_compatibility
Code
var f1 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function1 is done');
}
var f2 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function2 is done');
}
var f3 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function3 is done');
}
var f4 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function4 is done');
}
callbacks = function(){
// copy passed arguments
var callbacks = arguments;
// create array functions
var callbacks = Object.keys(callbacks).map(function(el){ return callbacks[el] });
var now = Date.now();
callbacks.reduce(function(previousPromise, currentFunc){
return previousPromise.then(
function(){
currentFunc();
var seconds = (Date.now() - now) / 1000;
console.log('Gone', seconds, 'seconds');
}
)
}, Promise.resolve());
}
callbacks(f1, f2, f3, f4);
Result in Chrome console (values seconds will be different):
Function1 is done
Gone 1.147 seconds
Function2 is done
Gone 2.249 seconds
Function3 is done
Gone 3.35 seconds
Function4 is done
Gone 4.47 seconds
Notes:
- It is does not work if a function contains a timer (for this problem I try also jQuery`s $Callbacks, $.Ajax and $.When but it not help. The only decision, what I found, usage resolve() in callback of a timer, but it is not acceptable if you have completed functions.).
- Testing environment
$ google-chrome --version
Google Chrome 53.0.2785.116

- 4,217
- 2
- 36
- 41
I just had a problem with my api provider that doing Promise.all() would end up in concurrency db problems..
The deal with my situation is that i need to get every promise result in order to show some "all ok" or "some got error" alert.
And i don't know why .. this little piece of code who uses reduce when the promises resolved i couldn't get my scope to work (too late to investigate now)
$scope.processArray = function(array) {
var results = [];
return array.reduce(function(p, i) {
return p.then(function() {
return i.then(function(data) {
results.push(data);
return results;
})
});
}, Promise.resolve());
}
So thanks to this post http://hellote.com/dynamic-promise-chains/ I came with this little bastard.. It's not polished but it's working all right.
$scope.recurse = function(promises, promisesLength, results) {
if (promisesLength === 1) {
return promises[0].then(function(data){
results.push(data);
return results;
});
}
return promises[promisesLength-1].then(function(data) {
results.push(data);
return $scope.recurse(promises, promisesLength - 1, results);
});
}
Then i invoke the function like this:
var recurseFunction = $scope.recurse(promises, promises.length, results);
recurseFunction.then(function (response) { ... });
I hope it helps.

- 730
- 6
- 14
To build on this answer, if you want to return the result of all those promises, too:
async function chainPromises(promises) {
let results = [];
for (let promise of promises) {
let result = await promise();
results.push(result);
}
return results;
}

- 11,934
- 4
- 45
- 73
Actually then
provides dynamic chaining because it immediately returns an equivalent Promise
object, allowing you to chain calls to other promise methods.
Let take a look on the the following code:
const promise = new Promise(resolve => setTimeout(() => resolve(1), 1000));
promise
.then(value => value + 10)
.then(value => value + 100)
.then(value => console.log(value)) // Prints: 111
We can rewrite this in a way:
const promise2 = promise.then(value => value + 10);
const promise3 = promise2.then(value => value + 100);
const promise4 = promise3.then(value => console.log(value)); // Prints: 111
As you can see from above we are able to append next then
separately one by one.
This is the generic approach to manage the promise chains by keeping the latest Promise
object:
class PromiseChain {
constructor(promise) {
this.promise = promise;
}
then(onFulfilled, onRejected) {
this.promise = this.promise.then(onFulfilled, onRejected);
}
}
const promiseChain = new PromiseChain(promise);
promiseChain.then(value => value + 10);
promiseChain.then(value => value + 100);
promiseChain.then(value => console.log(value)); // Prints: 111
It allows us to make the promise chains using conditions, loops etc., for instance:
const promiseChain2 = new PromiseChain(promise);
[
value => value + 10,
value => value + 100,
value => console.log(value),
]
.forEach(item => promiseChain2.then(item)); // Prints: 111

- 11,742
- 1
- 33
- 48
Check the following tutorial for
- programmatic (dynamic) chaining of javascript/node.js promises and
- Promise chaining using recursive functions
Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise

- 558
- 4
- 11