1. 程式人生 > >es6 async函式例項:按順序完成非同步操作

es6 async函式例項:按順序完成非同步操作

async函式例項:按順序完成非同步操作

實際開發中,經常遇到一組非同步操作,需要按照順序完成。比如,依次遠端讀取一組 URL,然後按照讀取的順序輸出結果。

ES6 Promise 的寫法如下。

  1. function logInOrder(urls){
  2. // 遠端讀取所有URL
  3. const textPromises = urls.map(url =>{
  4. return fetch(url).then(response => response.text());
  5. });
  6. // 按次序輸出
  7. textPromises.reduce((chain, textPromise)=>{
  8. return chain
    .then(()=> textPromise)
  9. .then(text => console.log(text));
  10. },Promise.resolve());
  11. }

上面程式碼使用fetch方法,同時遠端讀取一組 URL。每個fetch操作都返回一個 Promise 物件,放入textPromises陣列。然後,reduce方法依次處理每個 Promise 物件,然後使用then,將所有 Promise 物件連起來,因此就可以依次輸出結果。

這種寫法不太直觀,可讀性比較差。下面是 async函式實現。

  1. async function logInOrder(urls){
  2. for(const
    url of urls){
  3. const response = await fetch(url);
  4. console.log(await response.text());
  5. }
  6. }

上面程式碼確實大大簡化,問題是所有遠端操作都是繼發。只有前一個 URL 返回結果,才會去讀取下一個 URL,這樣做效率很差,非常浪費時間。我們需要的是併發發出遠端請求。

  1. async function logInOrder(urls){
  2. // 併發讀取遠端URL
  3. const textPromises = urls.map(async url =>{
  4. const response = await fetch(url);
  5. return
    response.text();
  6. });
  7. // 按次序輸出
  8. for(const textPromise of textPromises){
  9. console.log(await textPromise);
  10. }
  11. }

上面程式碼中,雖然map方法的引數是async函式,但它是併發執行的,因為只有async函式內部是繼發執行,外部不受影響。後面的for..of迴圈內部使用了await,因此實現了按順序輸出。