我正在学习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
在第二个承诺得到解决之前更新对象。
我该怎么做?
Promise.all 首先解决最后的承诺
Promise.all
根本无法解决您传递的承诺。 Promises 只是报告和观察异步操作结果的手段。在调用 Promise.all
时,您的两个 promise 所报告的操作 already in progress。
Promise.all
只是看着他们,等待他们安顿下来。就是这样。它根本不start或run它们。
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()
属性被扔掉了。
当您“等待 Promise.all”时,您正在并行运行所有承诺,因此无法保证它们的执行顺序。
如果你必须对调用进行排序,那么你需要在触发下一个之前“等待”每个承诺。
例如
let data = {};
await this.service1.getFirstPromiseData()
.then(result => {
data = {
...result
}
});
await this.getSecondPromiseData()
.then(result => {
data = {
...result,
...data
}
});