何时使用 Promises 延迟函数

When to make a function deferred using Promises

我正在为 Promises 使用 Q 节点库,我认为这个问题也适用于 Bluebird 库。

上下文

我有几个函数调用要对我自己的自定义函数和 node.js fs 风格的异步函数进行调用。

如果我正在调用这样的函数:

sync function

do_something = function (input) {
  // assign variables, do other sync stuff 
}

并需要上述功能发生 before 这个功能:

sync function

do_something_else = function (input) {
  // assign variable, do other sync stuff
}

then需要调用类似于以下的原生节点函数:

async function

writeData = function (obj, callback) {
  var deferred = Q.defer();
  fs.writeFile(obj.file, obj.datas, function (err, result) {
    if (err) deferred.reject(err);
    else deferred.resolve('write data completed');
  });
  return deferred.promise.nodeify(callback);
}

finally需要上面的实现before这个函数:

sync function

do_something_last = function (input) {
  // assign variable, do other sync stuff
}

问题

这里要做的 'right' 事情是为了让我的所有函数 'deferred' 或 promise 知道,以便我可以确保它们按顺序或以正确的顺序调用? 像这样:

do_something(variable)
.then(do_something_else)
.then(writeData)
.then(do_something_last)
.done();

或者我应该这样做并保持顺序(排序)?像这样:

var variable1 = 'test1.txt'
var variable2 = 'test2.txt'
var return_value = do_something(variable1);
var return_another_value = do_something_else(return_value); <--sync
writeData(return_another_value); <-- async function
var final_value = do_something_last(variable2);  <-- sync function
// could potentially have async calls again after a sync call
writeDataAgain(return_another_value); <-- async function

澄清

我的想法是,因为其中一些同步函数需要在异步之后触发,所以我需要让它们知道 Promise 以保持顺序正确,就像这样:

sync functions made promise aware

do_something = function (input) {
  var deferred = Q.defer();
  // assign variables, do other sync stuff 
  deferred.resolve(_output_result_);
  return deferred.promise;
}
do_something_else = function (input) {
  var deferred = Q.defer();
  // assign variables, do other sync stuff 
  deferred.resolve(_output_result_);
  return deferred.promise;
}
do_something_last = function (input) {
  var deferred = Q.defer();
  // assign variables, do other sync stuff 
  deferred.resolve('completed workflow');
  return deferred.promise;
}

这将允许我这样做:

do_something(variable)
.then(do_something_else) <-- these need to execute before writeData
.then(writeData) <-- a async node fs call to writeFile
.then(do_something_last) <-- I need this to happen after the writeDate
.done();

在我阅读了反馈后,我想我真正想问的是:

How do I create a function workflow, mixing non-promise sync and promise-aware async function calls, all the while keeping the ordering (or sequencing) of execution?

如果你只关心你的函数是否按顺序执行,那么这样做:

do_something(variable)
.then(do_something_else)
.then(writeData)
.then(do_something_last)
.done();

只有当您要传递这些变量(例如,传递给其他服务)或使用它们创建不同的承诺链时,您才将承诺分配给变量。

例如

var promise = do_something('123')

// two different promise chains

var task1 = promise.then(function(res){
  // logic
})

var task2 = promise.then(function(res){
  // other logic, independent from task1
})

just do this instead and keep the ordering like so:

writeData(return_another_value);
var final_value = do_something_last(variable2);

好吧,那根本行不通,因为 do_something_lastwriteData(…) 承诺 已解决 之后不会被调用。它会在 promise 创建并 returned 后立即开始。因此,如果您关心该特定订单并想等到数据写入,那么您 需要then 与回调一起使用:

var final_promise = writeData(return_another_value).then(function(writeResult) {
    return do_something_last(variable2);
});

一般规则是:

  • 使同步函数同步 - 不需要承诺
  • 使所有异步函数始终return成为承诺
  • 仅在 promisification
  • 的最低可能级别使用延迟

您可以将 同步函数放在 then 中,非承诺 return 值(甚至抛出的异常)在其中工作正常。 所以当你可以写你的序列时

Q('test1.txt')
.then(do_something)
.then(do_something_else)
.then(writeData)
.then(do_something_last.bind(null, 'test2.txt'))
.done();

看起来很奇怪。如果您近期出于某种原因不打算使 do_something 异步化,那么写入和读取通常更简单

writeData(do_something_else(do_something('test1.txt'))).then(function() {
    return do_something_last('test2.txt');
}).done();

诚然,有时候写起来更有吸引力

somePromise()
.then(doSomethingSynchronous)
.then(doSomethingAsynchronous)

somePromise
.then(function(res) { return doSomethingAsynchronous(doSomethingSynchronous(res)); })

即使它们功能相同。选择自己比较喜欢的风格,也比较连贯。