无法实现类似节点的 async.race 功能

Can't implement node-like async.race function

我想实现async.race功能

/*
 * 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);
}

这里的问题是 async.race([slower, faster]) returns 函数应该能够处理结果。但是它 return 目前我们还没有得到任何结果的功能。

这是我的代码。问题是如何在最后一行

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?
            }
        }
    }
}

存储函数,稍后再执行。你也在使用 arguments 而你应该简单地接受一个数组。

var async = {
    race: function(arr) {
        var finished = false,
            i, winner_err, winner_data, cb = console.log.bind(console);

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


        return function(fn) {
            cb = fn;
        }
    }
}

async.race([slower, faster])(function(err, winner) {
  console.log(err, 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);
}

问题是我们应该 return 立即处理函数,而必须用处理函数处理的结果可能会在以后(异步)检索。所以我们应该预测两个用例:

  1. 在我们检索要处理的结果(faster 函数结果)之前调用处理函数
  2. 我们检索结果后调用处理函数(faster 函数结果)

最后我以下一个实现结束:

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;
    }
}

用法:

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
});