如何从许多内部非阻塞函数调用中提前退出外部函数?

时间:2015-03-09 23:39:39

标签: javascript node.js asynchronous nonblocking

我正在编写async.parallel的幼稚实施作为学习练习。以下是文档中的说明:

  

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

我不确定如何提前退出,如果其中一个函数返回错误。我传递回调是一个错误,但当然其他功能继续执行。

以下是我到目前为止的情况;随时可以在您的机器上试用。

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

2 个答案:

答案 0 :(得分:1)

你必须在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布尔标志,或者您想要保存状态的任何内容,并在每次回调时检查它。

答案 1 :(得分:1)

  

但当然其他功能继续执行

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

  

我不确定如何退出

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


你的实施中的一些要点你没有做得对:

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

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