Let's assume we have a function foo(item, callback)
and a collection items
.
What I'd like to do is substitute every item in items
with the value returned by the execution of foo
on it, like Array.map()
does.
But here comes the problem: the result of foo
is yielded in the callback, so I have no access to it outside the callback itself (obviously I can't change foo
to meet my needs).
You could try an approach like
var results = [];
items.map((function(el) {
foo(el, function(result) {results.push(time)});
});
But then you can't know when your results
collection will be "ready".
I'm totally clueless. What should I do? What is the pattern?
EDIT: I'm more interested in Vanilla Javascript ways of achieve this than tools/libraries, that are anyway acceptable answers.
This becomes pretty trivial when using the async library.
async.each(items, function(el, callback) {
foo(el, function(result) {
callback(result);
});
}, function(results) {
doSomethingWith(results); //results being an array of the callbacked results.
});
In vanilla JS I'd do it like this:
var items = ['item 1', 'item 2', 'item 3']
function foo(item, callback) {
// this is provided just to test the async nature of your callback
setTimeout(function () {
callback.call(null, item + ' async')
}, Math.random() * 5000);
}
var results = [];
var count = 0;
items.forEach(function (element, index, array) {
foo(element, function (result) {
results[index] = result;
// the actual "ready" check
if (++count == items.length) {
// here you should notify your code that all items have been replaced
// after a random number of seconds between 1 and 5 in the current example, it should
// write ['item 1 async', 'item 2 async', 'item 3 async']
console.log(results);
}
})
});
I don't know if this is a pattern or the best way, but I think is simple and fast. Be aware that forEach works only in IE9+. For IE < 9 you could either use the jQuery .each or manually write a for loop (but be careful with closures and indices).