在履行时将promises数组转换为值数组

时间:2022-10-14 15:11:10

I'm after a function that would return a resolved value of a promise. Failing gracefully is definitely a bonus, but it's an assumed precondition that when the function is called the promise is ready to be resolved.

我正在使用一个能够返回promise的已解析值的函数。优雅地失败肯定是一个奖励,但它是一个假定的前提条件,当函数被调用时,承诺已准备好被解决。

While I'm working with webdriver.js promise implementation which allows the queue manipulations similar to below, I don't want to get too lost in semantics of queues/chains etc. For that reason alone, here is some pseudocode to cover what I'm trying to achieve:

虽然我正在使用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 <<<
});

NB: afaik Q.all() would not do what I'm after - it takes an array of promises and returns a promise of an array, not its resolved value. I'm only happy to be proved wrong.

注意:afaik Q.all()不会做我正在做的事情 - 它需要一个承诺数组并返回一个数组的承诺,而不是它的已解析值。我很高兴被证明是错的。

2 个解决方案

#1


3  

The only way to get the eventual value for a promise is with then. If a function performs work asynchronously, it must return a promise and under no circumstances can it return a plain value. To do so, it would necessarily have to block the thread of execution until the work completes, which is only possible with threads or fibers, which entrain the perils of deadlock and interleaving hazards.

获得承诺的最终价值的唯一方法就是当时。如果函数异步执行工作,它必须返回一个promise,在任何情况下都不能返回一个普通值。要做到这一点,它必须阻止执行的线程,直到工作完成,这只能通过线程或光纤来实现,这会带来死锁和交错危险的危险。

As such, Q.all is in fact the method you need, except to follow up with then to get the eventual value.

因此,Q.all实际上是您需要的方法,除了跟进然后获取最终值。

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

There are ways to cheat, of course. promise.inspect() will return an object describing the state of the promise, like {state: "fulfilled", value: value} if it’s ready, or {state: "rejected", error} if it failed, or {state: "pending"}, if it is not yet ready. If, as you say, you are guaranteed that the outputs promise, returned by Q.all has been fulfilled, you can do this:

当然,有办法欺骗。 promise.inspect()将返回一个描述promise的状态的对象,如{state:“fulfilled”,value:value}如果它已经准备好,或{state:“rejected”,error}如果失败,或者{state: “待定”},如果尚未准备好。如果你说保证Q.all返回的输出承诺已经完成,你可以这样做:

outputs = outputs.inspect().value

I don’t recommend this. The best way to know that a promise is resolved is to use then.

我不推荐这个。知道承诺得到解决的最好方法是使用then。

You could also just push values onto an outputs array of your making if you can also guarantee that all the outputs are ready through some external means.

如果您还可以通过某些外部手段保证所有输出都已准备就绪,您也可以将值推送到您的输出数组中。

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;

The best means, however, is to just use Q.all(outputs).then to get an event that is guaranteed to be after all the outputs are ready.

然而,最好的方法是使用Q.all(输出).then来确保在所有输出都准备好之后的事件。

#2


2  

Since you in general never know whether promises are resolved or not, you cannot simply transform them into a plain value. Q.all must return a promise since it cannot extract the values array from the async context. The only time you know that a promise has a value is in the success handler, and there you're getting the value anyway. You should not use another event system that tells you when a promise has settled - use the promise itself.

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

So instead of using queue.enqueue, just put Q.all(outputs).then(function(values){ /* do something */ }). However, if you cannot work around that, you might have a look at the Promise inspect debugging method: _.pluck(_.invoke(outputs, "inspect"), "value"). But notice that it might be easier not to store the values in promises then.

因此,不要使用queue.enqueue,只需输入Q.all(outputs).then(function(values){/ *做某事* /})。但是,如果你无法解决这个问题,你可能会看看Promise inspect的调试方法:_.pluck(_。invoke(outputs,“inspect”),“value”)。但请注意,然后可能更容易不将值存储在promises中。

#1


3  

The only way to get the eventual value for a promise is with then. If a function performs work asynchronously, it must return a promise and under no circumstances can it return a plain value. To do so, it would necessarily have to block the thread of execution until the work completes, which is only possible with threads or fibers, which entrain the perils of deadlock and interleaving hazards.

获得承诺的最终价值的唯一方法就是当时。如果函数异步执行工作,它必须返回一个promise,在任何情况下都不能返回一个普通值。要做到这一点,它必须阻止执行的线程,直到工作完成,这只能通过线程或光纤来实现,这会带来死锁和交错危险的危险。

As such, Q.all is in fact the method you need, except to follow up with then to get the eventual value.

因此,Q.all实际上是您需要的方法,除了跟进然后获取最终值。

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

There are ways to cheat, of course. promise.inspect() will return an object describing the state of the promise, like {state: "fulfilled", value: value} if it’s ready, or {state: "rejected", error} if it failed, or {state: "pending"}, if it is not yet ready. If, as you say, you are guaranteed that the outputs promise, returned by Q.all has been fulfilled, you can do this:

当然,有办法欺骗。 promise.inspect()将返回一个描述promise的状态的对象,如{state:“fulfilled”,value:value}如果它已经准备好,或{state:“rejected”,error}如果失败,或者{state: “待定”},如果尚未准备好。如果你说保证Q.all返回的输出承诺已经完成,你可以这样做:

outputs = outputs.inspect().value

I don’t recommend this. The best way to know that a promise is resolved is to use then.

我不推荐这个。知道承诺得到解决的最好方法是使用then。

You could also just push values onto an outputs array of your making if you can also guarantee that all the outputs are ready through some external means.

如果您还可以通过某些外部手段保证所有输出都已准备就绪,您也可以将值推送到您的输出数组中。

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;

The best means, however, is to just use Q.all(outputs).then to get an event that is guaranteed to be after all the outputs are ready.

然而,最好的方法是使用Q.all(输出).then来确保在所有输出都准备好之后的事件。

#2


2  

Since you in general never know whether promises are resolved or not, you cannot simply transform them into a plain value. Q.all must return a promise since it cannot extract the values array from the async context. The only time you know that a promise has a value is in the success handler, and there you're getting the value anyway. You should not use another event system that tells you when a promise has settled - use the promise itself.

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

So instead of using queue.enqueue, just put Q.all(outputs).then(function(values){ /* do something */ }). However, if you cannot work around that, you might have a look at the Promise inspect debugging method: _.pluck(_.invoke(outputs, "inspect"), "value"). But notice that it might be easier not to store the values in promises then.

因此,不要使用queue.enqueue,只需输入Q.all(outputs).then(function(values){/ *做某事* /})。但是,如果你无法解决这个问题,你可能会看看Promise inspect的调试方法:_.pluck(_。invoke(outputs,“inspect”),“value”)。但请注意,然后可能更容易不将值存储在promises中。