RxJS體驗
換一種思路來解決異步問題,最近在工作中遇到一個向后端輪詢倍靡,查詢桌面客服端是否啟動的問題,使用RxJS來處理復雜的異步流程课舍,真香塌西!
幾乎所有的網(wǎng)頁應用都是異步的,微任務筝尾,宏任務捡需,動畫,事件回調(diào)隊列......
- 腳本加載
- 播放器
- 數(shù)據(jù)訪問
- 動畫
- DOM事件
傳統(tǒng)異步編程存在的問題筹淫,這些也是RxJS能處理的問題
- 異步編程中的狀態(tài)(state)是難以追蹤的
- 使用回調(diào)時站辉,try...catch語法基本是沒用的
- 如果你監(jiān)聽了一個事件卻忘記了銷毀它,很容易造成的內(nèi)存泄露
如何用RxJs來實現(xiàn)
現(xiàn)要實現(xiàn)的請求需求如下
- 輪詢時間7s
- 每間隔1s一次损姜;
- 若有一次請求成功中止輪詢饰剥,返回成功結果
- 10秒內(nèi)未成功中止輪詢,返回失敗結果
如果使用Promise
// 1秒間隔
function sleep (ms: number) {
return new Promise((resolve,reject) => {
setTimeout(() => reject(new Error('請求后1s內(nèi)無響應')), 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內(nèi)無響應')), 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輪詢函數(shù)摧阅,檢查客戶端是否啟動
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操作符能函數(shù)式的解決復雜的異步流程汰蓉,從我一個RxJS新手來說優(yōu)點很多
- 代碼更簡潔,聲明式的代碼可讀性也更好
- 使用
純函數(shù)
來產(chǎn)生數(shù)據(jù)流(異步或同步)逸尖,沒有共享的代碼古沥,RxJS會將需要的狀態(tài)隔離起來,如果有問題也更容易定位
缺點也有娇跟,不過還是香
- 上手有一定難度
- 上百個操作符要完成掌握還是需要一些時間