How to deal with async functions and collections?

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).