I am given an array of functions of length N, where every function has an asynchronous call and accepts a callback argument. The callback of function[x] is function[x+1], and function[N-1] has no callback. Here's an example of what I might be given:
function func1(callback){
$.ajax({
//Ajax settings
}).done(function(){
console.log('foo1');
if(callback) callback();
});
}
function func2(callback){
$.ajax({
//Ajax settings
}).done(function(){
console.log('foo2');
if(callback) callback();
});
}
function func3(callback){
$.ajax({
//Ajax settings
}).done(function(){
console.log('foo3');
if(callback) callback();
});
}
var funcs = [func1, func2, func3];
Am I able to build the following nested calls for the example without just building a string and calling eval():
func1(function(){
func2(function(){
func3()
})
})
/*
Output:
foo1
foo2
foo3
*/
Edit: They have to be nested because I need them to run synchronously. For-loops or foreach() create race conditions.
Make a new function, which chains all the functions in the array:
funcx = funcs.reduceRight((f2, f1) => x => f1(f2(x)));
Then call this function:
funcx();
Of course, you could do it also in on step, but it might be a bit confusing:
funcs.reduceRight((f2, f1) => x => f1(f2(x)))();
If you want to be prepared for an empty array of functions, you can do it like this:
funcs.reduceRight((f2, f1) => x => f1(f2(x)), x => 0)();
Creating Promise can make the solution easy. Please follow the sample.
const delay = (v) => {
return new Promise(r => {
setTimeout(x => r(v), 10000 * Math.random())
})
}
async function dummyAjax() {
const data = await delay(Math.random() * 10)
return data
}
async function func1() {
return dummyAjax()
}
async function func2() {
return dummyAjax()
}
async function func3() {
return dummyAjax()
}
console.time("PROMISE: TOTAL_TIME")
Promise.all([func1(), func2(), func3()])
.then((responses) => {
responses.forEach(console.log)
console.timeEnd("PROMISE: TOTAL_TIME")
})
I have created a series of the solution on all types of async ways to addressing the issue. Please check my gist page.
https://gist.github.com/deepakshrma/1a899bf49ccb77d3b5be771907b32e4c
If all of your functions returned the promise, then your solution is easy. First, add a return
statement to each of your functions:
function func1(callback){
return $.ajax(...);
}
Then, you could just do this:
func1()
.then(func2)
.then(func3)
.then(result => console.log('DONE!', result))
.catch(err => console.log('OH NO!', err));
If you want to keep the array, then you can do this:
var funcs = [func1, func2, func3];
funcs.reduce((promise, func, i) => {
if(i === 0) return promise();
return promise.then(func);
})
.then(result => console.log('DONE!', result))
.catch(err => console.log('OH NO!', err));
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