如何打开数组方法链中的承诺数组



我有一个由多个映射组成的链,其中一个映射需要为每个数组元素执行数据库操作,所以我使用异步等待。

const resultsAsPromises = arr
.map(syncDouble)
.map(asyncMapper)

如果它是链中的最后一个项目,这不是问题,因为我可以用Promise.all打开它

console.log('results', await Promise.all(resultsAsPromises))

但是,之后我还需要执行其他同步操作,所以在转到下一个.map之前,我希望先打开promise的值。

有办法做到这一点吗?我想也许只是制作一个像这样的提取映射器

function extractPromiseValues(value) {
return value.then(v => v);
}

会起作用,但遗憾的是,不会。

var arr = [1, 2, 3, 4, 5];
function timeout(i) {
return new Promise((resolve) => {
setTimeout(() => {
return resolve(`number is ${i}`);
}, 1);
});
}
function syncDouble(i) {
return i * 2;
}
async function asyncMapper(i) {
return await timeout(i)
}
function extractPromiseValues(value) {
return value.then(v => v);
}
async function main() {
const resultsAsPromises = arr
.map(syncDouble)
.map(asyncMapper)
//     .map(extractPromiseValues)
console.log('results', await Promise.all(resultsAsPromises))
}
main();

如何打开数组方法链中的promise数组

与其将身份函数传递给.then(),不如传递同步操作,或者在将await传递给同步操作之前,先将async函数中的promise:

function syncCapitalize(s) {
return s.slice(0, 1).toUpperCase() + s.slice(1);
}
const resultsAsPromises = arr
.map(syncDouble)
.map(asyncMapper)
.map(p => p.then(syncCapitalize)); // OR
//.map(async p => syncCapitalize(await p));

在您的示例中,这看起来像:

function timeout(i) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`number is ${i}`);
}, 1);
});
}
function syncDouble(i) {
return i * 2;
}
function asyncMapper(i) {
return timeout(i);
}
function syncCapitalize(s) {
return s.slice(0, 1).toUpperCase() + s.slice(1);
}
async function main() {
const arr = [1, 2, 3, 4, 5];
const resultsAsPromises = arr
.map(syncDouble)
.map(asyncMapper)
.map(p => p.then(syncCapitalize)); // OR
//.map(async p => syncCapitalize(await p));
console.log('results', await Promise.all(resultsAsPromises));
}
main();

或者,如果我们像Ghassen Louhaichi那样解释这个问题,您可以使用TC39管道运营商(|>(提案,使用以下选项之一编写链:

F#管道方案

const results = arr
.map(syncDouble)
.map(asyncMapper)
|> Promise.all
|> await
.map(syncCapitalize);

智能管道方案

const results = (arr
.map(syncDouble)
.map(asyncMapper)
|> await Promise.all(#))
.map(syncCapitalize);

不幸的是,除非您使用的是Babel插件,或者直到其中一个提议被合并到官方ECMAScript规范中,否则您必须使用await Promise.all(...):来包装链

const results = (await Promise.all(arr
.map(syncDouble)
.map(asyncMapper)))
.map(syncCapitalize);

最后,在您的完整示例的上下文中:

function timeout(i) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`number is ${i}`);
}, 1);
});
}
function syncDouble(i) {
return i * 2;
}
function asyncMapper(i) {
return timeout(i);
}
function syncCapitalize(s) {
return s.slice(0, 1).toUpperCase() + s.slice(1);
}
async function main() {
const arr = [1, 2, 3, 4, 5];
const results = (await Promise.all(arr
.map(syncDouble)
.map(asyncMapper)))
.map(syncCapitalize);
console.log('results', results);
}
main();

最新更新