1. 程式人生 > >async/await的學習及在react-native中的使用

async/await的學習及在react-native中的使用

前言:最近新開了個RN的專案,網路請求用的是fetch,和以前的專案完全不一樣,以前都是用的 redux + redux-promise + redux-saga 這一套來處理非同步請求的。而在新專案中我們這邊使用ES6的 async/await 來處理非同步問題。

今天介紹一下我學習 async/await 的過程:

首先,說一下async的用法,它作為一個關鍵字放到函式前面,用於表示函式是一個非同步函式(async本身就是非同步的意思), 非同步函式也就意味著該函式的執行不會阻塞後面程式碼的執行。

其次,await必須在有關鍵字async的函式中使用

最後,async 函式返回的是一個promise 物件,如果要獲取到promise 返回值,我們應該用then 方法,程式碼如下:

async function timeout() {
    return 'hello world'
}
timeout().then(result => {
    console.log(result);
})
console.log('雖然在後面,但是我先執行');

上面程式碼得到的效果:

注意:Promise 有一個resolved,這是async 函式內部的實現原理。如果async 函式中有返回一個值 ,當呼叫該函式時,內部會呼叫Promise.solve() 方法把它轉化成一個promise 物件作為返回,但如果timeout 函式內部丟擲錯誤呢? 那麼就會呼叫Promise.reject() 返回一個promise 物件。

示例程式碼:

async function timeout(flag) {
    if (flag) {
        return 'hello world'
    } else {
        throw 'my god, failure'
    }
}
console.log(timeout(true))  // 呼叫Promise.resolve() 返回promise 物件。
console.log(timeout(false)); // 呼叫Promise.reject() 返回promise 物件。

結果:

還有就是,如果async函式內部丟擲錯誤, promise 物件有一個catch 方法進行捕獲,如:

timeout(false).catch(err => {
    console.log(err)
})

總結:async/await是解決非同步的一個方式,其實現原理來自於Promise,所以,Promise才是重點!

而await的作用就是在async(非同步)函式中等待一個promise的返回,==>> 個人理解,在async中實現同步,但await執行的卻是非同步!

虛擬碼:==>> 便於理解

第一種情況:單個Promise

async loadData(){
    //呼叫介面,獲取資料(介面是網上找的,不一定有用)
    fetch('https://www.baidu.com/search/error.html') // 返回一個Promise物件
      .then((res)=>{
         //介面呼叫正常,將呼叫Promise.resolve()
         return res.text() // res.text()是一個Promise物件 
      })
      .then((res)=>{
         //介面呼叫正常,將呼叫Promise.reject()
         console.log(res) // res是最終的結果
    })
}

第二種情況:多個Promise ==>> 容易造成 “回撥地獄”

“回撥地獄”:由於回撥函式或者網路請求是非同步的,在上面的程式碼中每一層的回撥函式都需要依賴上一層的回撥執行完,所以形成了層層巢狀的關係最終形成類似上面的回撥地獄,但程式碼以此種形式展現時無疑是不利於我們閱讀與維護的。

async loadData(){
    //呼叫介面,獲取資料(介面是網上找的,不一定有用)
    fetch('https://www.baidu.com/search/error.html') // 返回一個Promise物件
      .then((res)=>{
         //介面呼叫正常,將呼叫Promise.resolve()
         return res.text() // res.text()是一個Promise物件 

         fetch(url)        //網路請求2或回撥2 ==>> 第二個Promise
        .then((res)=>{
            ....           //網路請求n或回撥n ==>> 第n個Promise
        })
        .catch((err)=>{})

      })
      .catch((err)=>{
         //介面呼叫正常,將呼叫Promise.reject()
         console.log(err) // res是最終的結果
    })
}

總結:在上面這種情況中,在一個Promise中還有多個其他的Promise,裡面的Promise就必須依賴於上一次的回撥執行完成才可以繼續執行(需要注意的是:Promise本身是非同步的哦)。這樣的寫法程式碼會很多,並且不好維護,而且容易造成回撥地獄。這種時候await就比較好用了。

使用await:

async loadData(){
    //呼叫介面,獲取資料(介面是網上找的,不一定有用)
    let data1 = await ...;        //呼叫介面1

    let data2 = await ...;        //呼叫介面2

    let data3 = await ...;        //呼叫介面3
    
    console.log(data1,data2,data3);
}

在上面這種情況中:loadData()函式是非同步的,並且每一個介面的呼叫都是非同步的,但是每一次呼叫介面的時候都使用了await,使用它會等待第一個介面呼叫完成之後,在呼叫第二個介面,之後在呼叫第三個介面,相當於在loadData()這個非同步函式裡面的各個請求介面獲取資料直接 是同步的,但每一個請求介面的內部確實非同步的。這樣就沒有使用.then(()=>{}).catch(()=>{})這樣的寫法了,await是比較好維護並且好理解的。

最後,看一下 async/await 在react-native中的使用:

方式一:async定義函式,在其餘地方呼叫

方式二:直接對 componentWillMount 等生命週期方法使用async

文章僅為本人學習過程的一個記錄,僅供參考,如有問題,歡迎指出

對部落格文章的參考,若原文章博主介意,請聯絡刪除!請原諒