Node.js:从异步子函数的回调中调用异步父函数

时间:2014-11-24 17:33:44

标签: node.js asynchronous callback promise q

我正在尝试从另一个异步函数('parent')中调用异步函数('child')。为了使事情变得复杂,父函数公开了一个双API(回调+承诺)。这是使用Q库的 defer() nodeify()完成的,如下所示:

var parent = function(p_arg, callback) {

  var deferred = Q.defer();

  child(arg, function(err, cb_arg) {
    if(err)
      deferred.reject(err);
    else
      deferred.resolve(cb_arg);
  });

  //If a callback was supplied, register it using nodeify(). Otherwise, return a promise.
  if(callback)
    deferred.promise.nodeify(callback);
  else
    return deferred.promise;
}

请注意,子函数不会返回promise。现在,根据传递给子回调(cb_arg)的参数的值,我可能决定对父进行一次新的调用,尽管有一个修改过的参数(p_arg)。我如何记住父母API的双重性质?

这是我迄今为止所能提出的:

child(arg, function(err, cb_arg) {
  if(err)
    deferred.reject(err);
  else if(cb_arg.condition) {

    /*Make a fresh call to parent, passing in a modified p_arg*/
    if(callback)
      parent(p_arg + 1, callback);
    else
      deferred.promise = parent(p_arg + 1);
      /*
        ^ Is this the correct way to do this?
        My goal is to return the promise returned by the fresh parent() call,
        so how about I just assign it to the current parent() call's deferred.promise?
      */
  } 
  else
    deferred.resolve(cb_arg);
});

更新:好的,我对这个问题有一点清晰的认识。我现在认为实际需要做的是以下几点:

child(arg, function(err, cb_arg) {
  if(err)
    deferred.reject(err);
  else if(cb_arg.condition) {

    /*Make a fresh call to parent, passing in a modified p_arg*/
    if(callback)
      parent(p_arg + 1, callback);
    else
      parent(p_arg + 1)
      .then(function(p_ret) {
          deferred.resolve(p_ret);
      }, function(p_err) {
          deferred.reject(p_err);
      });
  } 
  else
    deferred.resolve(cb_arg);
});

这种模式似乎适用于我的特定用例。但是,如果这种方法存在明显的异步相关错误,请告诉我。

1 个答案:

答案 0 :(得分:0)

  

如何记住父级API的双重性质?

别。当你有可用时,只需使用promises。

顺便说一句,您可以使用Q.ncall而不是手动使用延迟。并且您无需明确测试回调,nodeify会在您通过undefined时处理它。

deferred.promise = parent(p_arg + 1);
     

这是正确的方法吗?   我的目标是返回新的parent()调用返回的promise,   那我怎么把它分配给当前的parent()调用的deferred.promise?

您将使用.then()并从回调中返回一个新的承诺来链接操作,为最后一个操作的结果获取新的承诺。

var promise = child().then(function(res) {
    if (condition(res))
        return parent(); // a promise
    else
        return res; // just pass through the value
});
  

更新:[...]此模式似乎适用于我的特定用例。

这是deferred antipattern的变体。你不想使用它。特别是,在传递回调的情况下,它似乎会留下一个悬挂(永不解决)延迟的附加回调。

你应该做的只是

function parent(p_arg, callback) {
    return Q.nfcall(child, arg)
    .then(function(cb_arg) {
        if (cb_arg.condition) {
            return parent(p_arg + 1, callback);
        else
            return cb_arg;
    })
    .nodeify(callback);
}