简体   繁体   English

为什么将 flatMap 与异步 function 一起使用不返回展平数组?

[英]Why does using flatMap with an async function not return a flatten array?

I want to understand why using .flatMap() with async does not return a flatten array.我想了解为什么将.flatMap()async一起使用不会返回展平数组。

For example, for Typescript, this returns an array of numbers: I know Promisse.all and async are useless with a simple array of number, it is just easier for reproduction例如,对于 Typescript,这将返回一个数字数组:我知道Promisse.allasync对于一个简单的数字数组是无用的,它只是更容易重现

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

When this, for Typescript, returns an array of array of numbers (just added an async):当这时,对于 Typescript,返回一个数字数组(刚刚添加了一个异步):

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

All async functions implicitly return Promises.所有async函数都隐式返回 Promise。 By making your .flatMap() callback async , it now returns a Promise that resolves to the number array.通过使您的.flatMap()回调async ,它现在返回一个解析为number数组的 Promise。 For .flatMap() to work correctly and for it to flatten its results, the callback should return an array, not a Promise:为了.flatMap()正常工作并使其结果变平,回调应该返回一个数组,而不是 Promise:

 (async () => { const numbers = [[1], [2], [3]]; const numbersFlatten = await Promise.all( 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(numbersFlatten); })();

Instead, you can use a regular .map() call to obtain a nested array of resolved values followed by a .flat() call:相反,您可以使用常规的.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); })();

I wanted to add that the fact Promise is eager also has performance implications.我想补充一点, 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[]>

You can see in the code above that we need to map , then flat , with this additional round trip through the microtasks queue because of the then in-between.您可以在上面的代码中看到,我们需要map ,然后是flat ,由于中间有then ,因此需要通过微任务队列进行额外的往返。 Doing this kind of round trip for the sake of playing Lego is wasteful.为了玩乐高而进行这种往返是浪费。

Note that if you don't write an asyncFlatMap helper you can avoid that then of course.请注意,如果您不编写asyncFlatMap帮助程序, then您当然可以避免这种情况。 I'm making a general statement here.我在这里做一个一般性的声明。

If you happen to nest promises a lot you may be interested in Fluture .如果你碰巧嵌套了很多 promise,你可能会对Fluture感兴趣。

Futures are lazy, so you can play Lego with them before anything is run. Futures 是惰性的,所以你可以在任何东西运行之前和它们一起玩乐高。

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[]>
);

In the code above I converted the Future back to a Promise with promise in order to match your use case.在上面的代码中,我将 Future 转换回 Promise 和promise以匹配您的用例。 It is only when this function is called that the computation is run.只有当这个 function 被调用时计算才会运行。 fork would also run the computation without ever involving promises. fork也可以在不涉及承诺的情况下运行计算。

In case you are not familiar with pipe : the first argument is the value which is threaded through the remaining function arguments.如果您不熟悉pipe :第一个参数是通过剩余的 function arguments 传递的值。

The magic value 10 in parallel is just the maximum number of computations to run concurrently. parallel的神奇值10只是并发运行的最大计算数。 It could have been anything else.它可能是其他任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM