运行 node 中的一系列异步函数未来需要在哪里?

Where is future necessary to run a sequence of async functions in node?

以前,我使用 future.wait() 来等待一个值,然后再 return 它到下一个函数。 (顺便说一句,我正在用 Meteor 编码)

在阅读了节点的非阻塞I/O架构之后,我的以下方法(确实有效)是否完全违背了目的?

我所做的是将以下'requesting'函数的返回结果传递给另一个函数。相反,回调方法是最好的约定吗?

我使用 future 的唯一原因是因为使用 return 会立即执行。我想学习最佳实践,因为我认为我正在使用 future 添加额外的不必要代码层。

如果我使用回调约定 callback(null, result),是否 'callback' 等待对象被传递到参数中?

我的代码使用 future 来等待结果:

function requesting(perm_data) {
  var f = new future();
  request.get('example.com/api/auth_user', {
    oauth: {consumer_key:'somekey',
            token: perm_data.oauth_token,
            token_secret: perm_data.oauth_token_secret
            }
  }, function response(error, response, body) {
  if (!error && response.statusCode === 200) {
    var bodyToJson = parser.toJson(body, options)
    var userId = bodyToJson.user.id
       return f.return(userId)
  }
  else {
    f.throw(error)
  }
})
  return f.wait()
}


function nextFunction(data) {
 //do some thing with data
 } 

Meteor.methods({
 sequenceAsyncFunctions: function() {
  try {
     var resultOne = requesting()
     var resultTwo = nextFuntion(resultOne)
      } catch (e) {
      //handling my errors
      }
  }
})

'callback' wait for objects to be passed into the arguments

实际上回调并不等待对象。回调由您为其提供参数的函数使用参数调用。


您可以使用 promise 库之一,例如 Q 来处理这个问题

这里有一些文章更深入地描述了它

一些备选方案是 Kew and Async

已指定承诺,您可以在此处查看更多详细信息和库:http://wiki.commonjs.org/wiki/Promises/A

我注意到您在服务器上标记了这个问题 . Meteor uses Fibers。该软件包使用一种轻量级线程(称为纤程)为您提供协作式多任务处理。这使您可以像 requesting 一样编写 "blocking" 函数,而不会实际阻塞事件循环。 Future 允许您使用纤程以阻塞方式使用基于回调的 node.js 函数。

如果没有 Fibers,就不可能编写出像您的 requesting 这样直接执行 I/O 和 returns 结果的函数。相反,您必须传递回调(或使用承诺)。

惯用的 Meteor 代码应该使用服务器上的 Fibers 来实现 "blocking" 功能。这就是核心 Meteor API 的工作方式,并且在 Meteor 方法中是必需的。您可能会发现 Meteor.wrapAsync 比使用 future 更方便。

在常规 node.js 代码中,您可以使用纤程,但更常见的是使用 function (err, result) {...} 回调或承诺。在浏览器中(包括 Meteor 客户端代码)你不能使用 Fibers,所以你必须使用回调或承诺。

以下是如何使用 future、常规回调和承诺对操作进行排序:

// Future
function doTwoThings() {
    var future = new Future();
    asyncFunction(argument, function (err, result) {
        if (err) future.throw(err);
        else future.return(result);
    });
    var result = future.wait();

    var future2 = new Future();
    anotherAsyncFunction(result, function (err, result2) {
        if (err) future2.throw(err);
        else future2.return(result2);
    });
    var result2 = future2.wait();
    return result2 + 2;
}

// wrapAsync
var wrappedAsyncFunction = Meteor.wrapAsync(asyncFunction);
var wrappedAnotherAsyncFunction = Meteor.wrapAsync(anotherAsyncFunction);
function doTwoThings() {
    var result = wrappedAsyncFunction(argument);
    var result2 = wrappedAnotherAsyncFunction(anotherAsyncFunction);
    return result2 + 2;
}

// Regular callbacks
function doTwoThings(callback) {
    asyncFunction(argument, function (err, result) {
        if (err) return callback(err);

        anotherAsyncFunction(result, function (err, result2) {
            if (err) return callback(err);
            callback(null, result2 + 2);
        });
    });
}

// Promises
function doTwoThings() {
    return asyncFunctionReturningPromise(argument).then(function (result) {
        return anotherAsyncFunctionReturningPromise(result);
    }).then(function (result2) {
        return result2 + 2;
    });
}