【问题标题】:How to exit outer function early from one of many inner non-blocking function calls?如何从许多内部非阻塞函数调用之一中提前退出外部函数?
【发布时间】:2015-03-10 08:22:46
【问题描述】:

我正在编写一个简单的 async.parallel 实现作为学习练习。以下是文档中的描述:

parallel(tasks, [callback]) 运行 tasks 数组中的函数 并行,无需等到前一个函数完成。 如果任何函数将错误传递给其回调,则主 立即使用错误的值调用回调。一旦 任务已完成,结果将传递给最终回调 一个数组。

我不确定如何提前退出,以防其中一个函数返回错误。我向回调传递了一个错误,但当然其他函数会继续执行。

以下是我目前所拥有的;随意在您的机器上试用。

function parallel(tasks, cb) {
  cb = cb || function() {};

  if (!Array.isArray(tasks)) return cb('tasks must be an array');  
  if (!tasks.length) return cb();

  var res = [];
  var completed_count = 0;

  for (var i=0; i<tasks.length; i++) {
    (function(ind) {
      tasks[ind](function(err, val) {
    if (err) return complete(err); // <--- ! 
    res[ind] = val;
    completed_count++;
    if (completed_count === tasks.length) complete(null, res);
      });
    } (i));
  }
};


// ===== test functions =====
function slow(time, cb) {
  setTimeout(function() {
    cb(null, time);
  }, time);
};

function slowError(time, cb) {
  setTimeout(function() {
    cb('Some Error', time);
  }, time);
}

function complete(err, results) {
  if (err) return console.log(err);
  else return console.log(results);
};


// ===== tests =====
// should return [1000, 2000, 3000]
parallel([slow.bind(null, 1000),
          slow.bind(null, 2000),
          slow.bind(null, 3000)], complete);

// should exit early
parallel([slowError.bind(null, 1000),
          slowError.bind(null, 2000),
          slow.bind(null, 3000)], complete);

【问题讨论】:

    标签: javascript node.js asynchronous nonblocking


    【解决方案1】:

    当然其他函数会继续执行

    是的。而且您不能对此采取任何措施,因为他们没有为您提供取消它们的方法。 async.js 也不做任何事情,你只需要让它们运行。

    我不知道如何提前退出

    但“让他们跑”并不意味着你必须等待他们。您可以立即触发回调 - 这是他们正在谈论的“立即”退出。


    在你的实现中有些地方你没有完全正确:

    • 确保在不 - 绝对不 - 多次调用callback。用户期望你做到这一点,如果你不这样做,他们的应用就会发疯。
    • 您应该能够处理不正确的任务,并多次调用您的函数表达式
    • 重申第 1 点:进一步的错误应该被忽略
    • 您可能希望在完成后防止内存泄漏和垃圾收集结果数组,即使某些任务仍然持有对您的函数表达式的引用

    我会把这些作为练习留给你:-)

    【讨论】:

      【解决方案2】:

      您必须将整个执行的状态存储在parallel 函数中,并在每个回调中检查这一点:应该是处于错误/完成状态的状态,每个下一个回调都应该被解除。像这样的:

      function parallel(tasks, cb) {
        var result = [];
        var await = tasks.length;
        tasks.forEach(function(task, i){
          task(function(err, val){
            if (await === 0) return;
            if (err) {
              await = 0;
              cb(err);
              return;
            }
            result[i] = val;
            if (--await === 0) cb(null, result);
          })
        });
      }
      

      这里我使用倒计时来匹配结束或完成状态。例如,您还可以使用 errored 布尔标志,或者您想要保存状态并在每次回调时检查它的任何内容。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-01
        • 2018-06-12
        • 2018-09-23
        • 1970-01-01
        • 2018-10-12
        • 2011-08-10
        • 1970-01-01
        • 2014-10-01
        相关资源
        最近更新 更多