【问题标题】:Can't implement node-like async.race function无法实现类似节点的 async.race 功能
【发布时间】:2015-10-22 01:34:52
【问题描述】:

我要实现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?
            }
        }
    }
}

【问题讨论】:

    标签: javascript node.js asynchronous callback


    【解决方案1】:

    存储函数,稍后再执行。你也使用了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);
    }

    【讨论】:

    • 这有一个缺点。您正在测试的两个函数必须是异步的。如果它们是同步的,则测试不会产生有用的结果,并且不会调用回调。
    • 如果我只调用async.race([slower, faster])会发生什么?我想cb 永远不会被初始化,但它会作为faster 函数的回调调用
    • 会出错。如果这是您想要处理的可能性,则需要对其进行修改以处理它。 cb &amp;&amp; cb(err, data) 应该这样做,除非您想做更多的事情,例如在没有 cb 的情况下记录哪个更快。
    • 抱歉,我需要一个通用函数,可以重复使用。在这种情况下调用console.log 而不是用户的函数是没有意义的
    • 所以您是在询问关于什么是最好的意见,而没有具体说明什么是最好的意思?
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 2021-01-13
      • 2016-11-20
      相关资源
      最近更新 更多