Q:

Can't implement node-like async.race function

I want to implement async.race function
/*
 * Takes array of functions and returns a handler-function of result of the fastest btw arguments
 */
async.race([slower, faster])(function(err, winner) {
  console.log(winner); // I'm faster
});

function slower(callback) {
    setTimeout(callback.bind(null, null, "I'm slower"), 1000);
}

function faster(callback) {
  setTimeout(callback.bind(null, null, "I'm faster"), 10);
}

The problem here is that async.race([slower, faster]) returns function which should be able to handle results. BUT it return the function at the moment we haven't got any result. 
Here's my code. The question is how to be at the last line
var async = {
    race: function() {
        var args = Array.prototype.slice.call(arguments), 
            finished = false,
            i, winner_err, winner_data;

        var callback = function(err, data) {
            if (finished) return;
            else finished = true;

            winner_err = err;
            winner_data = data;
        }

        for (i  = 0; i < args.length; i++) {
            args[i](function(err, data) {
                if (finished) return;
                else finished = true;
            });
        }

        return function(fn) {
            if (finished) {
                fn(winner_err, winner_data);
            } else {
                //QUESTION: how to be here. I need return function with not ready `winner_data` and check in while/setInterval when the results will appear?
            }
        }
    }
}

A:

The problem was that we should return handler-function immediately, while the result which must be handled with the handler-function may be retrieved later (asynchronously). So we should predict two usecases:

Handler-function is called before we retrieve the result (faster function result) to be handled
Handler-function is called after we retrieve the result (faster function result)

Finally I end with next implementation:
var async = {
    // @param array - array of a functions
    // @return returns a function which accept handler-function as 
    // an argument. The handler function will handle the result of the 
    // fastest btw {@param array} functions  
    race: function(arr) {
            // indicates if the first (fastest) function is completed. 
            // If yes - there is no sense to handle another functions results
        var finished = false, 
            //  Returned errors / data of the first (fastest) function
            winner_err, winner_data, 
            // callback which will handle the results of the fastest function
            cb, i;

        var retur_func = function(fn) {
            // For the case if `smth_like_promise` (see Usage section) will be called 
            // before `faster` will be completed
            cb = fn;    
            // For the  case if `faster` will be completed before 
            // `smth_like_promise` will be called
            if (retur_func.redefined) retur_func.redefined(fn);
        };

        // callback which handle the result of each separate function that participates in race
        var callback = function(err, data) {
            if (finished) return;

            finished = true;
            // Tricky situation: we have data to be handled, but haven't handler function
            if (!cb) {
                // We pass `return_func` to the client and can't redefine it. 
                // So we redefine it property, which will be called instead function in future 
                retur_func.redefined = function(fn) {
                    fn(err, data);
                }
            } else {
                cb(err, data);
            }

        }

        // Start race! Afterwards only the first function results should be
        // handled with `retur_func` function
        for (i  = 0; i < arr.length; i++) {              
            arr[i](callback);
        }

        return retur_func;
    }
}

Usage:
var slower = function(cb) {
    setTimeout(cb.bind(null, null, "I'm slower"), 1000);
}

var faster = function(cb) {
  setTimeout(cb.bind(null, null, "I'm faster"), 10);
}

var smth_like_promise = async.race([slower, faster]); 

// you may call `smth_like_promise` immediately or wait until passed functions (`faster` or `slower`) will be completed
smth_like_promise(function(err, winner) {
  alert(winner); // I'm faster
});

