如何使用Ramda.js链式处理Promise?新手技术求助
用Ramda.js链式处理Promise并合并异步数据的正确姿势
问题出在哪
你拿到Promise { <pending> }是因为Ramda的普通函数(比如R.map)不会自动处理Promise——它会直接操作Promise对象本身,而不是等它resolve之后再处理结果。得用专门的异步辅助函数来衔接Promise流程。
正确实现方案
1. 先并行拿数据
getMongoDBMaterials和getCMSMaterials是独立的异步操作,用Promise.all同时发起请求比串行await快得多,不用等一个完了再等另一个。
2. 用Ramda的pipe+andThen串起异步流程
Ramda的R.andThen(以前叫R.then)就是用来在Promise resolve后执行后续逻辑的,和Promise原生的.then()功能一样,但更适合和R.pipe搭配做链式调用。
3. 优化合并函数(更贴合Ramda风格)
你的mergeResponse可以用Ramda自带的函数简化,不用写原生map和Object.assign,代码更简洁也更符合函数式风格。
完整代码
// 先修正getCMSMaterials的返回类型(应该是数组,所以改成Promise<CMSMaterial[]>) getCMSMaterials(): Promise<CMSMaterial[]> { return lastValueFrom( this.httpService .get(`${this.apiUrl}/materials`) .pipe(map((resp) => resp.data)), ); } // 优化后的合并函数 private mergeResponse = R.curry((key = '_id', cmsList: CMSMaterial[], mongoList: Material[]) => { // zipWith按索引配对两个数组的元素,merge合并每一对对象的属性 return R.zipWith(R.merge, mongoList, cmsList); }); // 链式异步处理的正确写法 const getAndMergeMaterials = async () => { return R.pipe( // 第一步:并行发起两个异步请求 () => Promise.all([this.getMongoDBMaterials(), this.getCMSMaterials()]), // 第二步:等请求都完成后,把结果传给合并函数 R.andThen(([mongoList, cmsList]) => this.mergeResponse('_id', cmsList, mongoList)) )(); }; // 使用的时候直接await就行 const finishedMaterials = await getAndMergeMaterials();
代码解释
Promise.all:一次性启动两个异步任务,返回的Promise会在两个任务都完成后resolve,结果是包含两个数组的列表。R.andThen:专门处理Promise的链式步骤,前面的Promise resolve后,会把结果传给后面的函数执行。R.zipWith+R.merge:替代你原来的map+Object.assign,按索引把两个数组里的对象一一合并,代码更简洁。
要是想用R.compose(反向链式)
R.compose是从右往左执行,写法稍微调整一下:
const getAndMergeMaterials = async () => { return R.compose( R.andThen(([mongoList, cmsList]) => this.mergeResponse('_id', cmsList, mongoList)), () => Promise.all([this.getMongoDBMaterials(), this.getCMSMaterials()]) )(); };
为啥你的尝试写法不对?
- 你写的
this.getMongoDBFinishes()应该是this.getMongoDBMaterials()的笔误吧? R.map直接怼在Promise上,会去遍历Promise对象的内部属性,不是等它resolve后遍历数组——必须先用andThen等Promise完成再处理结果。- 最后加
Promise.all.bind(Promise)完全没用,前面的步骤根本没返回Promise数组。
内容的提问来源于stack exchange,提问作者Exodus Reed
相关产品推荐
相关产品推荐

