动态

详情 返回 返回

angular 8+中使用observable使用async/await - 动态 详情

不廢話,直接上結論,jsobservable不能直接使用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)
  }

顯而易見,執行結果是
image.png

那麼,我想像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)
  }

啊哈,不好,編輯器提示了
image.png

不信邪,運行看看
image.png

正如上面説的,流程控制並沒有起作用,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方法才行。
image.png
可以看到,現在程序會等待promise執行完畢以後才會輸出2,也就是流程控制生效了。

注意 有些朋友手動寫observable的時候,沒有在裏面寫complete,這樣執行toPromise的時候,並不會運行then裏面代碼,因為promise在底層代碼完成之前是不會進行解析的,也就是手寫observable中一定要記得寫complete

當然,轉換成promise並不能解決一切問題,比如下面這種情況

當用户點開頁面的時候,需要同時發出50個請求,但是用户很可能在所有數據請求結束之前就會跳走,所以很可能20-30個請求都是無效請求,那麼,無效請求就需要直接取消掉

我們知道promise是不能夠取消已經發出的請求的,你可以通過throw或者reject觸發promisecatch操作,但是這只是代表你不再對發出請求的結果關心,請求依然存在,結果依然會返回。
除非用户在所有請求完成之前點擊了瀏覽器的停止加載按鈕,
image.png
那請求就會從pending狀態變成了cancel
image.png
image.png

或者,使用subscribe,這也是其對比promise的優勢之一
取消subscribe請求很簡單:
單個請求的情況下

   this.observable.subscribe((res)=>{}).unsubscribe()

直接在後面加上unsubscribe就行,這個請求會變成cancel狀態,不會再佔用請求資源

那麼, 回到上面的問題,簡化一下就是,我可不可以,即能取消已經發出的請求,又能控制代碼的流程呢?答案是肯定的,只要把promiseobservable一起搭配使用就行
第二種解決辦法、 終極版代碼如下

  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()
  }

運行結果為
image.png

思路就是通過promise控制代碼流程,然後利用對象接收Observable,控制請求的取消與否

這樣,即可以按照自己的意願隨時取消已經發出的請求,同時,也能控制代碼的流程

Add a new 评论

Some HTML is okay.