我正在使用一个能够返回promise的已解析值的函数。优雅地失败肯定是一个奖励,但这是一个假定的前提条件,当函数被调用时,承诺已准备好解决。
虽然我正在使用允许类似于下面的队列操作的webdriver.js promise implementation,但我不希望在队列/链的语义等方面太丢失。仅仅因为这个原因,这里有一些伪代码涵盖我想要实现的目标:
var inputs = [...], outputs;
outputs = inputs.map(function(input){
//queue some async tasks to be performed with input
queue.enqueue(...);
//I can't return the *output* value here yet, naturally, so instead
return promise;
});
//now I'll add another task to the same queue
//this means that by the time this task is run
//the async tasks above would have been executed
//and the promises would be "resolvable"... right?
queue.enqueue(function(){
console.log(outputs); //>an array of promises
console.log(doSomeMagic(outputs)); //>resolved values as needed <<<
});
注意:afaik Q.all()
将不做我正在做的事情 - 它需要一系列承诺并返回一个数组的承诺,不是它的已解析值。我很高兴被证明是错的。
答案 0 :(得分:3)
获取承诺的最终价值的唯一方法是使用then
。如果函数异步执行工作,它必须返回一个promise,在任何情况下都不能返回一个普通值。要做到这一点,它必须阻止执行的线程,直到工作完成,这只能通过线程或光纤来实现,这会带来死锁和交错危险的危险。
因此,Q.all
实际上是您需要的方法,但要跟进then
以获取最终值。
Q.all(inputs.map(function (input) {
return promiseForOutput; // however you go about this
}))
.then(function (outputs) {
// at this event, outputs is an array of output values
});
当然,还有办法欺骗。 promise.inspect()
将返回描述承诺状态的对象,如{state: "fulfilled", value: value}
已准备好,或{state: "rejected", error}
如果失败,或{state: "pending"}
,如果尚未准备好。如果如您所说,保证outputs
承诺已由Q.all
返回,则可以执行以下操作:
outputs = outputs.inspect().value
我不推荐这个。了解承诺得到解决的最佳方法是使用then
。
如果您还可以通过某种外部方式保证所有outputs
都已准备就绪,您也可以将值推送到outputs
数组。
var endResult = Q.defer();
var outputs = [];
inputs.forEach(function (input) {
outputPromise.then(function (output) {
outputs.push(output);
check();
}, endResult.reject);
});
check();
function check() {
if (outputs.length === inputs.length) {
// manipulate outputs directly, they are ready
endResult.resolve();
}
}
return endResult.promise;
然而,最好的方法是使用Q.all(outputs).then
来确保在所有输出准备就绪后保证事件。
答案 1 :(得分:2)
由于您通常不知道承诺是否得到解决,因此您不能简单地将它们转换为普通值。 Q.all
必须返回一个promise,因为它无法从异步上下文中提取values数组。唯一一次你知道一个promise有一个值就在成功处理程序中,无论如何你都会得到这个值。您不应该使用另一个事件系统来告诉您承诺何时结算 - 使用承诺本身。
所以而不是使用queue.enqueue
,只需添加Q.all(outputs).then(function(values){ /* do something */ })
。但是,如果您无法解决此问题,可以查看Promise inspect
debugging method:_.pluck(_.invoke(outputs, "inspect"), "value")
。但请注意,那么将值存储在promises中可能会更容易。
答案 2 :(得分:2)
对于其他根据问题标题寻找答案的人,以下与ES 2017+结合使用以实现承诺数组并返回值数组:
var arrayOfValues = await Promise.all(arrayOfPromises)