Node.js 如何按顺序在Q中链接可变数量的承诺?
我见过;我的问题不同 如何按顺序进行可变数量的调用,每个调用异步返回?Node.js 如何按顺序在Q中链接可变数量的承诺?,node.js,promise,q,Node.js,Promise,Q,我见过;我的问题不同 如何按顺序进行可变数量的调用,每个调用异步返回? 该场景是一组HTTP请求,其数量和类型由第一个HTTP请求的结果决定 我想简单地做到这一点 我也看到过类似的情况: var q = require('q'), itemsToProcess = ["one", "two", "three", "four", "five"]; function getDeferredResult(prevResult) { return (function (someResul
该场景是一组HTTP请求,其数量和类型由第一个HTTP请求的结果决定 我想简单地做到这一点 我也看到过类似的情况:
var q = require('q'),
itemsToProcess = ["one", "two", "three", "four", "five"];
function getDeferredResult(prevResult) {
return (function (someResult) {
var deferred = q.defer();
// any async function (setTimeout for now will do, $.ajax() later)
setTimeout(function () {
var nextResult = (someResult || "Initial_Blank_Value ") + ".." + itemsToProcess[0];
itemsToProcess = itemsToProcess.splice(1);
console.log("tick", nextResult, "Array:", itemsToProcess);
deferred.resolve(nextResult);
}, 600);
return deferred.promise;
}(prevResult));
}
var chain = q.resolve("start");
for (var i = itemsToProcess.length; i > 0; i--) {
chain = chain.then(getDeferredResult);
}
…但以这种方式循环使用ItemStopProcess似乎很尴尬。或者定义一个名为“loop”的新函数来抽象递归。什么方法更好?我更喜欢这种方法:
var q = require('q'),
itemsToProcess = ["one", "two", "three", "four", "five"];
function getDeferredResult(a) {
return (function (items) {
var deferred;
// end
if (items.length === 0) {
return q.resolve(true);
}
deferred = q.defer();
// any async function (setTimeout for now will do, $.ajax() later)
setTimeout(function () {
var a = items[0];
console.log(a);
// pop one item off the array of workitems
deferred.resolve(items.splice(1));
}, 600);
return deferred.promise.then(getDeferredResult);
}(a));
}
q.resolve(itemsToProcess)
.then(getDeferredResult);
这里的关键是调用.then()
,使用拼接版本的工作项数组调用deferred.promise
。该然后在初始延迟承诺解析后运行,该承诺位于setTimeout的fn中。在更现实的场景中,延迟承诺将在http客户端回调中得到解决
初始的q.resolve(itemsToProcess)
通过将工作项传递给工作fn的第一个调用来启动工作
我添加这个是希望它能帮助其他人。这里是一个用Q
定义的状态机概念
假设您定义了HTTP函数,因此它返回一个Q
promise对象:
var Q_http = function (url, options) {
return Q.when($.ajax(url, options));
}
您可以定义递归函数nextState
,如下所示:
var states = [...]; // an array of states in the system.
// this is a state machine to control what url to get data from
// at the current state
function nextState(current) {
if (is_terminal_state(current))
return Q(true);
return Q_http(current.url, current.data).then(function (result) {
var next = process(current, result);
return nextState(next);
});
}
其中,function process(current,result)
是根据HTTP调用的current
状态和result
找出下一步的函数
使用时,请像以下那样使用:
nextState(initial).then(function () {
// all requests are successful.
}, function (reason) {
// for some unexpected reason the request sequence fails in the middle.
});
有一个很好的干净的方法来解决这个问题
遍历数组,传入上一次迭代的返回值。在这种情况下,您将返回承诺,因此每次链接时,都会返回。您提供了一个初始承诺(就像您在q.resolve(“开始”)
中所做的那样)来启动事情
起初,你可能需要一段时间来了解这里正在发生的事情,但如果你花一点时间来了解它,那么这是一种易于在任何地方使用的模式,而不必设置任何机器。我提出了另一种解决方案,这看起来更容易理解。
当直接链接承诺时,您将执行相同的操作:
promise.then(doSomethingFunction).then(doNothingFunction)代码>
如果我们将其放入一个循环中,我们得到:
var chain = Q.when();
for(...) {
chain = chain.then(functionToCall.bind(this, arg1, arg2));
};
chain.then(function() {
console.log("whole chain resolved");
});
var functionToCall = function(arg1, arg2, resultFromPreviousPromise) {
}
我们使用多个参数。在我们的例子中
functionToCall.bind(this,arg1,arg2)
将返回一个带有一个参数的函数:functionToCall(resultFromPreviousPromise)
您不需要使用前面承诺的结果。按照第一个示例,在循环中构建.then()
链可能比递归更正常。无论您选择哪种方式,不要破坏原始阵列可能很重要。如果是这样,那么您可以让承诺(及其回调)使用在原始未受污染数组上运行的递增索引值。sweet!而且非常方便!如果承诺被拒绝,会发生什么?或者,至少,我们应该如何处理这种情况?@naivedeveloper如果一个步骤被拒绝,那么下面的步骤将不会被执行,chain
也将被拒绝,因此您可以使用chain.catch
来捕捉这种情况。非常好的解决方案。谢谢这是完美的,融化了我的大脑,直到我看到它运行。这对我来说比其他while循环解决方案更有意义。它也更容易适应其他Promise库。这似乎不是一个可变的Promise数,而是一个取决于数组长度的集合数。有些情况下,您实际上有一个可变的数字,我不确定reduce
方法是否适用于这些情况。将作为官方参考
var chain = Q.when();
for(...) {
chain = chain.then(functionToCall.bind(this, arg1, arg2));
};
chain.then(function() {
console.log("whole chain resolved");
});
var functionToCall = function(arg1, arg2, resultFromPreviousPromise) {
}