javascript 为什么flatMap与async函数一起使用时不返回扁平数组?

ar7v8xwq  于 2023-01-01  发布在  Java
关注(0)|答案(2)|浏览(139)

我想了解为什么将.flatMap()async一起使用不会返回扁平数组。
例如,对于Typescript,这将返回一个数字数组:* 我知道Promisse.allasync对于简单的数字数组是无用的,它只是更容易复制 *

const numbers = [[1], [2], [3]];
// typed as number[]
const numbersFlatten = await Promise.all(
    numbers.flatMap((number) => number),
);

对于Typescript,如果这样,则返回数字数组的数组(只是添加了一个异步):

const numbers = [[1], [2], [3]];
// typed as number[][]
const numbersFlatten = await Promise.all(
    numbers.flatMap(async (number) => number),
);
am46iovg

am46iovg1#

所有async函数都隐式返回Promise。通过使.flatMap()回调为async,它现在返回解析为number数组的Promise。为使.flatMap()正常工作并使其结果扁平化,回调应返回数组,而不是Promise:

const numbers = [[1], [2], [3]];
const promiseAllArg = numbers.flatMap(async (number) => number); // same as `.flatMap(number => Promise.resolve(number))`, flatMap doesn't know how to flatten `Promise<number>` into a resulting array
console.log(promiseAllArg); // [Promise<[1]>, Promise<[2]>, Promise<[3]>]

相反,您可以使用常规.map()调用来获取解析值的嵌套数组,后跟.flat()调用:

(async () => {
  const numbers = [[1], [2], [3]];
  const numbersFlatten = (await Promise.all(
    numbers.map(async (number) => number)
  )).flat() // flatten the resolved values
  console.log(numbersFlatten);
})();
35g0bw71

35g0bw712#

我想补充的是,Promise的渴望也会影响性能。

const asyncFlatMap = <A, B>(arr: A[], f: (a: A) => Promise<B>) =>
    Promise.all(arr.map(f)).then(arr => arr.flat());

asyncFlatMap([[1], [2], [3]], async nums => nums); // Promise<number[]>

从上面的代码中可以看到,我们需要map,然后flat,由于then的存在,我们需要在微任务队列中进行额外的往返,为了玩Lego而进行这种往返是很浪费的。
注意如果你不写asyncFlatMap帮助器,你当然可以避免then,我在这里做一个一般性的声明。
如果你碰巧嵌套了很多承诺,你可能会对Fluture感兴趣。
期货是懒惰的,所以你可以在任何东西运行之前和他们玩乐高。

import { resolve, parallel, promise, map } from 'fluture';
import { pipe } from 'fp-ts/function';

const numbersFlatten = await pipe(
    numbers.map(nums => resolve(nums)), // Future<number[]>[]
    parallel(10), // Future<number[][]>
    map(x => x.flat()), // Future<number[]>
    promise // Promise<number[]>
);

在上面的代码中,我用promise将Future转换回Promise,以匹配您的用例。只有当调用此函数时,计算才会运行。fork也会在不涉及Promise的情况下运行计算。
如果您不熟悉pipe:第一个参数是贯穿其余函数参数的值。
parallel中的magic值10只是并发运行的最大计算数,它可以是任何其他值。

相关问题