Reputation: 1116
Say I have an array of objects which have asynchronous methods:
[
{
partOne: function(input) {
// Do something async
},
partTwo: function(result) {
// Do something w/ result of partOne
}
},
{
partOne: function(resultOfPrevious) {
// Do something async
},
partTwo: function(result) {
// Do something w/ result of partOne
}
},
{
partOne: function(resultOfPrevious) {
// Do something async
},
partTwo: function(result) {
// Do something w/ result of partOne
}
}
]
I want to execute partOne of the first object with my input, pass the result (async) to the partTwo callback, then pass the result of partTwo as input to partOne of the next object and so on. The array may be of one or more objects. I'm wondering what the best pattern to execute this kind of code is?
It is somewhat similar to the waterfall method of async.js: https://caolan.github.io/async/docs.html#waterfall, but I wonder how I can do this without a library and possibly with cleaner code?
Not sure if async/await might help here?
Upvotes: 0
Views: 604
Reputation: 1969
Assuming your array of objects given in the original question is under a variable called waterfall
let collector = [];
for (waterfallObj of waterfall) {
let tempArr = Object.values(waterfallObj);//get the functions out of the object
for (waterfallFunc of tempArr) {
collector.push(waterfallFunc);
}
}
//now you have your functions in order in collector
function recursiveCallback(i) {
if (i>collector.length-1) {
return;//if there are no more to call then return
}
collector[i]().then(function(){
recursiveCallback(i+1);
});
}
If you want the next function to do something with the previous functions value then simply change the then to then(function(passedValue and then use that passedValue in the recursiveCallback call within it
Upvotes: 0
Reputation: 257
Here is a simple function to invoke each asynchronous function in a stack
function drain(stack, initialArg) {
stack.reduce(function (sectArg, section) {
return Object.keys(section).reduce(async function (arg, key) {
return await section[key].call(null,arg)
}, sectArg)
}, initialArg)
}
To use it ensure that each function in you stack returns a value
var stack = [
{
partOne: function(input) {
// Do something async
console.log('section one partOne', input)
return 'section one partOne output'
},
partTwo: function(result) {
// Do something w/ result of partOne
console.log('section one partTwo', result)
return 'section one partTwo output'
}
},
{
partOne: function(resultOfPrevious) {
// Do something async
console.log('section two partOne', resultOfPrevious)
return 'section two partOne output'
},
partTwo: function(result) {
// Do something w/ result of partOne
console.log('section two partTwo', result)
return 'section two partTwo output'
}
},
{
partOne: function(resultOfPrevious) {
// Do something async
console.log('section three partOne', resultOfPrevious)
return 'section three partOne output'
},
partTwo: function(result) {
// Do something w/ result of partOne
console.log('section three partTwo', result)
return 'section three partTwo output'
}
}
]
So that you can invoke the stack like
drain(stack, 'initialArg')
See this jsfiddle: https://jsfiddle.net/kqj0rror/
Upvotes: 1
Reputation: 2241
Another option without collecting every callback to an array, using async/await
:
async function processWaterfallObject (data, input) {
let result = input
for (let entry of data) {
result = await entry.partOne(result)
result = await entry.partTwo(result)
}
return result
}
This assumes that functions in your data
array are either async
or return a Promise
.
async/await
is currently supported by every major browser and is available in node
since 7.6.0
.
Upvotes: 2