在承诺中使用异步/等待
Using Async / Awaits within promise
我的代码中有一个特定的承诺链,如下所示:
myPromise()
.then(getStuffFromDb)
.then(manipulateResultSet)
.then(manipulateWithAsync)
.then(returnStuffToCaller)
现在,在我的 manipulateWithAsync 中,我试图通过再次调用数据库来增强我的结果集,但它没有像我预期的那样工作,因为在调试时我发现了控制移动到下一个函数,即 returnStuffToCaller
下面是我的 manipulateWithAsync 函数的想法:
function manipulateWithAsync(rs) {
return rs.map( async function whoCares(singleRecord) {
let smthUseful = await getMoreData(singleRecord.someField);
singleRecord.enhancedField = smthUseful;
return singleRecord;
})
}
我明白了这种行为的要点:map 函数确实按预期工作,并且 promise 链不在乎它,因为它不与等待一起工作。
有没有办法让我的 returnStuffToCaller 函数等到异步函数完成他的工作?
我也使用 bluebird,我尝试使用 coo-routine,所以如果你认为这是一个很好的解决方案,我会 post 我的 bluebird coo-routine 失败代码:)
谢谢!
问题在于将 async/await 与 Array.map
一起使用
这个答案应该有帮助:
rs.map 迭代器跳转到下一个元素,而无需在每个单独的迭代中等待。
你需要像 asyncMap 这样的东西
您可以使用 - https://github.com/caolan/async
或者自己实现
async function asyncMap(array, cb) {
for (let index = 0; index < array.length; index++) {
return await cb(array[index], index, array);
}
}
*cb 函数必须是异步函数
用 Promise.all
return 包裹你的地图,然后 Promise
然后 await
在你调用 manipulateWithAsync
.
的地方得到结果
// MOCKS FOR DEMO
// Test data used as input for manipulateWithAsync
const testData = [
{ recordNumber: 1 },
{ recordNumber: 2 },
{ recordNumber: 3 }
];
// Mock function which returns Promises which resolve after random delay ranging from 1 - 3 seconds
const getMoreData = () =>
new Promise(resolve => {
const calledAt = Date.now();
setTimeout(() => {
resolve({
usefulData: `Promise called at ${calledAt}`
});
}, Math.floor(Math.random() * 3000) + 1000);
});
// SOLUTION / ANSWER
const manipulateWithAsync = async rs =>
Promise.all(
rs.map(async singleRecord => {
const smthUseful = await getMoreData(singleRecord.someField);
// Instead of manipulating original data,
// which might cause some unwanted side effects going forward,
// instead return new objects
return { ...singleRecord, enhancedField: smthUseful };
})
);
await manipulateWithAsync(testData);
我的代码中有一个特定的承诺链,如下所示:
myPromise()
.then(getStuffFromDb)
.then(manipulateResultSet)
.then(manipulateWithAsync)
.then(returnStuffToCaller)
现在,在我的 manipulateWithAsync 中,我试图通过再次调用数据库来增强我的结果集,但它没有像我预期的那样工作,因为在调试时我发现了控制移动到下一个函数,即 returnStuffToCaller
下面是我的 manipulateWithAsync 函数的想法:
function manipulateWithAsync(rs) {
return rs.map( async function whoCares(singleRecord) {
let smthUseful = await getMoreData(singleRecord.someField);
singleRecord.enhancedField = smthUseful;
return singleRecord;
})
}
我明白了这种行为的要点:map 函数确实按预期工作,并且 promise 链不在乎它,因为它不与等待一起工作。 有没有办法让我的 returnStuffToCaller 函数等到异步函数完成他的工作?
我也使用 bluebird,我尝试使用 coo-routine,所以如果你认为这是一个很好的解决方案,我会 post 我的 bluebird coo-routine 失败代码:)
谢谢!
问题在于将 async/await 与 Array.map
这个答案应该有帮助:
rs.map 迭代器跳转到下一个元素,而无需在每个单独的迭代中等待。 你需要像 asyncMap 这样的东西 您可以使用 - https://github.com/caolan/async 或者自己实现
async function asyncMap(array, cb) {
for (let index = 0; index < array.length; index++) {
return await cb(array[index], index, array);
}
}
*cb 函数必须是异步函数
用 Promise.all
return 包裹你的地图,然后 Promise
然后 await
在你调用 manipulateWithAsync
.
// MOCKS FOR DEMO
// Test data used as input for manipulateWithAsync
const testData = [
{ recordNumber: 1 },
{ recordNumber: 2 },
{ recordNumber: 3 }
];
// Mock function which returns Promises which resolve after random delay ranging from 1 - 3 seconds
const getMoreData = () =>
new Promise(resolve => {
const calledAt = Date.now();
setTimeout(() => {
resolve({
usefulData: `Promise called at ${calledAt}`
});
}, Math.floor(Math.random() * 3000) + 1000);
});
// SOLUTION / ANSWER
const manipulateWithAsync = async rs =>
Promise.all(
rs.map(async singleRecord => {
const smthUseful = await getMoreData(singleRecord.someField);
// Instead of manipulating original data,
// which might cause some unwanted side effects going forward,
// instead return new objects
return { ...singleRecord, enhancedField: smthUseful };
})
);
await manipulateWithAsync(testData);