5

我正在寻找一个返回一个已解决的承诺值的函数。优雅地失败绝对是一个好处,但它是一个假定的前提条件,即当函数被调用时,promise 已准备好被解决。

虽然我正在使用webdriver.js 承诺实现,它允许类似于下面的队列操作,但我不想太迷失在队列/链等的语义中。仅出于这个原因,这里有一些伪代码来涵盖我的内容'正在努力实现:

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 <<<
});

注意:afaikQ.all()不会我所追求的 - 它需要一个承诺数组并返回一个数组的承诺,而不是它的解析值。我很高兴被证明是错误的。

4

3 回答 3

6

对于根据问题标题寻找答案的其他人,以下适用于 ES 2017+ 以获取一组承诺并返回一组值:

var arrayOfValues = await Promise.all(arrayOfPromises)
于 2019-07-31T19:57:13.400 回答
4

获得承诺最终价值的唯一方法是使用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()将返回一个描述 Promise 状态的对象,例如{state: "fulfilled", value: value}它是否准备好,或者{state: "rejected", error}它是否失败,或者{state: "pending"},如果它还没有准备好。如果,正如您所说,您可以保证outputs由返回的承诺Q.all已经履行,您可以这样做:

outputs = outputs.inspect().value

我不推荐这个。知道 promise 已解决的最好方法是使用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获取保证在所有输出都准备好之后发生的事件。

于 2013-08-30T23:29:02.243 回答
3

由于您通常不知道 Promise 是否已解决,因此您不能简单地将它们转换为普通值。Q.all必须返回一个承诺,因为它无法从异步上下文中提取值数组。只有在成功处理程序中才知道一个 Promise 有一个值,并且无论如何你都会得到这个值。你不应该使用另一个事件系统来告诉你一个 Promise 什么时候完成 - 使用 Promise 本身。

所以不要使用queue.enqueue,只需放Q.all(outputs).then(function(values){ /* do something */ }). 但是,如果你不能解决这个问题,你可以看看Promiseinspect调试方法_.pluck(_.invoke(outputs, "inspect"), "value")。但请注意,那时不将值存储在 Promise 中可能更容易。

于 2013-08-30T10:22:46.193 回答