实现时,将承诺数组转换为值数组

Transform array of promises into array of values when fulfilled

本文关键字:数组 转换 承诺 实现      更新时间:2023-09-26

我正在寻找一个函数,该函数将返回promise的解析值。优雅地失败无疑是一种奖励,但这是一个假定的前提条件,即当调用函数时,promise就可以得到解决。

当我使用webdriver.js promise实现时,它允许类似于下面的队列操作,我不想在队列/链等的语义中迷失太多。仅出于这个原因,这里有一些伪代码来覆盖我试图实现的内容:

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()不会做我要做的事情-它接受一个promise数组,并返回一个数组的promise,而不是其解析值。我很高兴被证明是错的。

对于其他想要根据问题标题寻找答案的人,以下与ES 2017+一起使用,以获取一系列承诺并返回一系列值:

var arrayOfValues = await Promise.all(arrayOfPromises)

获取promise最终值的唯一方法是使用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"}(如果它尚未准备好)。如果,正如你所说,你保证Q.all返回的outputs承诺已经实现,你可以这样做:

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来获得一个事件,该事件保证在所有输出就绪之后发生。

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

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