不廢話,直接上結論,js中observable不能直接使用async/await這種流程控制標識,舉個例子
observable:Observable<any> = new Observable;
constructor() {
this.observable = Observable.create((item:any)=>{//一秒鐘後輸出結果
setTimeout(()=>{
item.next('結果');
item.complete();
},1000)
})
}
ngOnInit() {
console.log(1);
let startTime = new Date().getTime()
this.observable.subscribe((res)=>{
let endTime = new Date().getTime()
let result = Math.floor(new Date(endTime-startTime).getTime()/1000);
console.log(res,' 耗時',result,'秒')
})
console.log(2)
}
顯而易見,執行結果是
那麼,我想像promise那樣使用async/await是否可以呢?
對ngOnInite()方法進行稍加改動,加上async/await
async ngOnInit() {
console.log(1);
let startTime = new Date().getTime()
await this.observable.subscribe((res)=>{
let endTime = new Date().getTime()
let result = Math.floor(new Date(endTime-startTime).getTime()/1000);
console.log(res,' 耗時',result,'秒')
})
console.log(2)
}
啊哈,不好,編輯器提示了
不信邪,運行看看
正如上面説的,流程控制並沒有起作用,Observable不支持直接的流程控制。
解決辦法有兩個,首先説一個簡單情況下的解決辦法
第一種、轉為promise 操作如下
async ngOnInit() {
console.log(1);
let startTime = new Date().getTime()
await this.observable.toPromise().then((res)=>{
let endTime = new Date().getTime()
let result = Math.floor(new Date(endTime-startTime).getTime()/1000);
console.log(res,' 耗時',result,'秒')
})
console.log(2)
}
直接利用.toPromise()方法將其轉為promise,這樣async/await就起作用了,當然,也要使用promise中的then方法才行。
可以看到,現在程序會等待promise執行完畢以後才會輸出2,也就是流程控制生效了。
注意 有些朋友手動寫observable的時候,沒有在裏面寫complete,這樣執行toPromise的時候,並不會運行then裏面代碼,因為promise在底層代碼完成之前是不會進行解析的,也就是手寫observable中一定要記得寫complete
當然,轉換成promise並不能解決一切問題,比如下面這種情況
當用户點開頁面的時候,需要同時發出50個請求,但是用户很可能在所有數據請求結束之前就會跳走,所以很可能20-30個請求都是無效請求,那麼,無效請求就需要直接取消掉
我們知道promise是不能夠取消已經發出的請求的,你可以通過throw或者reject觸發promise的catch操作,但是這只是代表你不再對發出請求的結果關心,請求依然存在,結果依然會返回。
除非用户在所有請求完成之前點擊了瀏覽器的停止加載按鈕,
那請求就會從pending狀態變成了cancel
或者,使用subscribe,這也是其對比promise的優勢之一
取消subscribe請求很簡單:
單個請求的情況下
this.observable.subscribe((res)=>{}).unsubscribe()
直接在後面加上unsubscribe就行,這個請求會變成cancel狀態,不會再佔用請求資源
那麼, 回到上面的問題,簡化一下就是,我可不可以,即能取消已經發出的請求,又能控制代碼的流程呢?答案是肯定的,只要把promise和observable一起搭配使用就行
第二種解決辦法、 終極版代碼如下
observableArray:Subscription=new Subscription;
observable:Observable<any> = new Observable;
constructor() {
this.observable = Observable.create((item:Observer<any>)=>{
setTimeout(()=>{
item.next('完成');
item.complete();
},1000)
})
}
async ngOnInit() {
console.log(1);
let startTime = new Date().getTime()
await new Promise((resolve,reject)=>{
this.observableArray.add(this.observable.subscribe((res)=>{
resolve(true)
let endTime = new Date().getTime()
let result = Math.floor(new Date(endTime-startTime).getTime()/1000);
console.log(res,' 耗時',result,'秒')
}))
})
console.log(2)
}
ngOnDestroy(): void {
this.observableArray.unsubscribe()
}
運行結果為
思路就是通過promise控制代碼流程,然後利用對象接收Observable,控制請求的取消與否
這樣,即可以按照自己的意願隨時取消已經發出的請求,同時,也能控制代碼的流程