Promise.all 首先解决最后的承诺

问题描述 投票:0回答:2

我正在学习promises,已经走到了死胡同。所以我有这两个承诺,第一个从数据库中获取数据并返回一个承诺并更新

data
对象,最后一个是我做出的承诺,因为最终数据对象取决于第一个承诺的解析值。

假设

data
是我将使用第一个承诺中已解决的承诺值更新的对象。所以这是它的样子:

let promises = [];
let data = {};

promises.push(
  this.service1.getFirstPromiseData()
    .then(result => {
       data = {
         ...result
       }
    })
);

promises.push(
  this.getSecondPromiseData()
    .then(result => {
       data = {
         ...result,
         ...data
       }
    })
);

await Promise.all(promises);

getSecondPromiseData
是我的承诺,用来自第一个承诺的数据处理一些自定义数据。所以这是它的样子:

getThirdPromiseData() {
  return new Promise((resolve, reject) => {
      resolve({ name: 'John Doe' });      
  });
}

现在,如果我将

data
对象的值记录在第二个承诺的
then
中,我得到空对象。另外,如果我记录第二个承诺的
result
的值,它看起来比第一个承诺更早解决,因为它立即记录值..

我需要第一个承诺得到解决,并且

data
在第二个承诺得到解决之前更新对象。

我该怎么做?

javascript node.js promise
2个回答
1
投票

Promise.all 首先解决最后的承诺

Promise.all
根本无法解决您传递的承诺。 Promises 只是报告和观察异步操作结果的手段。在调用 Promise.all 时,您的两个 promise 所报告的操作
already in progress
Promise.all
只是看着他们,等待他们安顿下来。就是这样。它根本不startrun它们。

Re settlement(不是“决议”)这些承诺的相对时间:这取决于他们所报告的行动是做什么的。如果第二个比第一个更快地解决,那么就会发生这种情况。它与数组中承诺的顺序无关。


在回复对您所说问题的评论的评论中:

我以为

promise.all
按顺序解决。

如果您给

Promise.all
的所有承诺都已实现,
Promise.all
将使用这些实现值的数组来实现其承诺,并保证数组中的元素与您给它的承诺的顺序相同。但这与承诺何时结算无关,只是它们在数组中的顺序。

这是一个例子:请注意,无论您多久运行一次此代码,结果数组始终是

["A", "B", "C"]

function example(delay, value) {
    return new Promise((resolve) => {
        setTimeout(
            () => {
                console.log(`Fulfilling with ${value}`);
                resolve(value);
            },
            delay
        );
    });
}

// Waits a full second before fulfilling with "A"
const promiseA = example(1000, "A");

// Waits almost not time before fulfilling with "B"
const promiseB = example(0, "B");

// Waits half a second before fulfilling with "C"
const promiseC = example(500, "C");

// But the fulfillment value array from Promise.all is
// always in the order of the promises you give it
Promise.all([
    promiseA,
    promiseB,
    promiseC,
])
.then((result) => {
    console.log(result);
});

Promise.all
按顺序给你结果的原因是你知道哪个承诺产生了哪个结果。这与时间无关。


关于“和解”与“决议”(以及其他承诺术语),请参阅我的博客文章


在您提出的评论中:

嘿,你认为我如何更新我的代码来实现我想要的?

你说过这两件事可以并行运行,但在构建之前你需要两个结果

data
。这正是
Promise.all
的用途,所以您的技巧是正确的。以下是您的操作方式:

// Run the actions in parallel, wait until you have both results
const [firstResult, secondResult] = await Promise.all([
    this.service1.getFirstPromiseData(),
    this.getSecondPromiseData(),
]);
// ...use `firstResult` and `secondResult` here...

在您的问题中,您使用这两个结果来构建一个对象。如果这真的是你想要的,那么:

const data = {
    ...firstResult,
    ...secondResult,
};

但请注意,以这种方式使用结果意味着

secondResult
中与
firstResult
中的属性具有相同键的任何属性将“胜过”
firstResult
中的属性。例如,如果
firstResult
是一个像
{a: 1, b: 2, c: 3}
的对象,而
secondResult
是一个像
{a: "one"}
的对象,那么最后
data
将有一个具有
{a: "one", b: 2, c: 3}
的对象——来自
a
this.service1.getFirstPromiseData()
 属性
被扔掉了。


0
投票

当您“等待 Promise.all”时,您正在并行运行所有承诺,因此无法保证它们的执行顺序。

如果你必须对调用进行排序,那么你需要在触发下一个之前“等待”每个承诺。

例如

let data = {};

await this.service1.getFirstPromiseData()
    .then(result => {
       data = {
         ...result
       }
    });

await this.getSecondPromiseData()
    .then(result => {
       data = {
         ...result,
         ...data
       }
    });
© www.soinside.com 2019 - 2024. All rights reserved.