RxJS体验
换一种思路来解决异步问题,最近在工作中遇到一个向后端轮询,查询桌面客服端是否启动的问题,使用RxJS来处理复杂的异步流程,真香!
几乎所有的网页应用都是异步的,微任务,宏任务,动画,事件回调队列......
- 脚本加载
- 播放器
- 数据访问
- 动画
- DOM事件
传统异步编程存在的问题,这些也是RxJS能处理的问题
- 异步编程中的状态(state)是难以追踪的
- 使用回调时,try...catch语法基本是没用的
- 如果你监听了一个事件却忘记了销毁它,很容易造成的内存泄露
如何用RxJs来实现
现要实现的请求需求如下
- 轮询时间7s
- 每间隔1s一次;
- 若有一次请求成功中止轮询,返回成功结果
- 10秒内未成功中止轮询,返回失败结果
如果使用Promise
// 1秒间隔
function sleep (ms: number) {
return new Promise((resolve,reject) => {
setTimeout(() => reject(new Error('请求后1s内无响应')), ms)
})
}
// 串行请求
async function tenToAjax() {
for(let i = 0; i < 10; i++){
try {
await Promise.race([fetch('url'), sleep(1000)])
break
} catch(err){
console.log(err)
}
}
}
//10s时间
function ten () {
return new Promise((reject) => {
setTimeout(() => reject(new Error('10s内无响应')), 10000)
})
}
const polling = Promise.race([tenToAjax(), ten()])
polling.then(v => console.log(v)).catch(e => console.log(e));
如果使用RxJS
import { switchMap, filter, take, timeout } from 'rxjs/operators';
import { Observable, of, Subject, interval } from 'rxjs';
// 10s轮询函数,检查客户端是否启动
function pollingIsOpenClient(uid: string) {
const getPollingDate$ = interval(1000).pipe(
switchMap(() => getIsOpenClient(uid)),
filter((res: any) => res.body.launchId === uid),
take(1),
timeout(10000)
);
return getPollingDate$;
}
利用RxJS操作符能函数式的解决复杂的异步流程,从我一个RxJS新手来说优点很多
- 代码更简洁,声明式的代码可读性也更好
- 使用
纯函数
来产生数据流(异步或同步),没有共享的代码,RxJS会将需要的状态隔离起来,如果有问题也更容易定位
缺点也有,不过还是香
- 上手有一定难度
- 上百个操作符要完成掌握还是需要一些时间