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

时间:2015-07-30 15:34:06

标签: javascript node.js asynchronous callback

我想实现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])返回应该能够处理结果的函数。但它在我们没有得到任何结果的那一刻返回功能。

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

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

2 个答案:

答案 0 :(得分:1)

存储该功能,然后再执行。当你应该使用arguments时,你只需要接受一个数组。

&#13;
&#13;
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);
}
&#13;
&#13;
&#13;

答案 1 :(得分:0)

问题是我们应该立即返回handler-function,而必须使用handler-function处理的结果可以稍后(异步)检索。所以我们应该预测两个用例:

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

    最后,我以下一个实施结束:

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