如何避免fp-ts中TE.traverseArray遇Either Left时短路?
问题分析与解决方案
首先修正你代码里的语法错误:safeImport的定义多了一个右括号,正确写法是:
const safeImport = TE.tryCatchK((s) => import(s), tError);
两种写法输出差异的原因
你看到的输出差异,核心是TE.traverseArray的特性导致的:
TE.traverseArray是短路式遍历——它的作用是把Array<T>转换为TaskEither<E, Array<A>>,只要数组中有一个元素处理失败(返回Left),整个操作会立刻返回这个Left,不会继续处理后续元素。所以你只看到了第一个失败的结果,其他成功的元素根本没被执行。- 第二种写法用
A.map(safeImport)得到Array<TaskEither<E, A>>,每个元素都是独立的异步Either操作,后续的A.map(async x => console.log(await x()))会逐个执行所有操作,不管前面的元素成功或失败,因此能看到所有Left和Right。
实现“保留所有Left和Right”的需求
如果你想保留所有元素的成功/失败状态,同时将批量异步操作的结果统一收集,可以这样写:
const tError = (err) => err instanceof Error ? err : Error("unexpected error"); const safeImport = TE.tryCatchK((s) => import(s), tError); export const run = (globString) => pipe( glob.sync(globString), A.map(safeImport), // 得到 Array<TaskEither<E, A>> // 并行执行所有异步操作,收集所有结果 TE.parArray(Infinity), async (tasks) => { const allResults = await tasks(); console.log(allResults); // allResults 是 Array<Either<E, A>>,包含所有 Left 和 Right return allResults; } );
或者用更直观的Promise.all实现:
export const run = (globString) => pipe( glob.sync(globString), A.map(safeImport), A.map(TE.toPromise), // 把 TaskEither 转为 Promise<Either<E,A>> Promise.all, async (allResults) => { console.log(allResults); return allResults; } );
内容的提问来源于stack exchange,提问作者Ricardo Silva
相关产品推荐
相关产品推荐

