async/await 的基礎使用及原理簡介


async/await是es7推出的一套關於異步的終極解決方案,為什么要說他是終極解決方案呢?因為他實在是太好用了,而且寫起來還非常的簡單。

一:async/await基礎語法

// 定義一個異步函數(假設他是一個異步函數)
getJSON(){
    return 'JSON'
}

// 在需要使用上面異步函數的函數前面,加上async聲明,聲明這是一個異步函數
async testAsync() {
  // 在異步函數前面加上await,函數執行就會等待用await聲明的異步函數執行完畢之后,在往下執行
  await getJSON()
  
  ...剩下的代碼
}

以上就是async/await最基本的用法。

還需要注意的一點就是使用async/await的時候,是無法捕獲錯誤的,這個時候就要用到我們es5里面一個被大家遺忘了的try/catch,來進行錯誤的捕獲:

async testAsync() {
  try {
     await getJSON()
  } catch(err) {
     console.log(err)
  }
  ...剩下的代碼
}

注意:

1.async函數在聲明形式上和普通函數沒有區別,函數聲明式,函數表達式,對象方法,class方法和箭頭函數等都可以聲明async函數。

2.任何一個await語句后面的 Promise 對象變為reject狀態,那么整個async函數都會中斷執行。

3.async函數返回的 Promise 對象,必須等到內部所有await命令后面的 Promise 對象執行完,才會發生狀態改變,除非遇到return語句或者拋出錯誤。也就是說,只有async函數內部的異步操作執行完,才會執行then方法指定的回調函數。

二:async/await

async
async這個單詞大家應該都比較熟悉,他是英文單詞‘異步’的簡寫,代表的意思也是異步。

async function testAsync() {
    return "hello async";
}

const result = testAsync();
console.log(result);

輸出結果:

Promise{<resolved>: "hello async"}

可以看出async函數,返回的是一個Promise對象

await
await是英文單詞‘等待’的意思,代表的意思也是等待,那他等的到底是個什么東西呢?還是一個Promise。

三 async/await和Generator

Generator函數:generator(生成器)是ES6標准引入的新的數據類型。一個generator看上去像一個函數,但可以返回多次。下面面是一個Generator函數的簡單寫法。

function* Generator() {
            yield '11111111';
            yield '22222222'
            return '3333333';
        }

        let aaa = Generator();

Generator函數和普通函數一樣通過函數名+()去調用,但是調用完之后並不執行。它僅僅是創建了一個generator對象,還沒有去執行它。想要運行Generator函數,需要通過遍歷器對象的next方法。

    let a = aaa.next()
    let b = aaa.next()
    let c = aaa.next()
    let d = aaa.next()
    console.log(a,b,c,d) //  {value: "11111111", done: false}     {value: "22222222", done: false}      {value: "3333333", done: true}     {value: undefined, done: true}

想要Generator函數執行下一步,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式或return語句。由此可見,Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法可以恢復執行。也就是上面說的可以交出函數的執行權。

上面對Generator函數做了一個簡單的介紹,接下來說一下async/await和Generator。

根據阮一峰老師的介紹,async函數就是Generator函數的語法糖。

圖片:

代碼上看起來,async函數就是將 Generator 函數的星號(*)替換成async,將yield替換成await。

實際上async函數對Generator函數的改進,體現在一下四點:

1.async函數自帶執行器,所以執行方式和普通函數的執行方式一樣,通過函數名+()的方式執行。

2.async和await比起*和yield在語義上更清楚。

3.co模塊約定,yield命令后面只能是 Thunk 函數或 Promise 對象,而async函數的await命令后面,可以是 Promise 對象和原始類型的值(數值、字符串和布爾值,但這時會自動轉成立即 resolved 的 Promise 對象)。

4.async函數的返回值是 Promise 對象,這比 Generator 函數的返回值是 Iterator 對象方便多了。你可以用then方法指定下一步的操作。

進一步說,async函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而await命令就是內部then命令的語法糖。

四:async/await和Promise
上面說了async/await和Generator的關系,這里再說一下和Promise的關系,async/await其實是基於Promise的。async函數其實是把Promise包裝了一下。

下面是一個async/await的寫法:

 getConstant() {
   return 1
 }

 async getAsyncConstant() { 
  return 1
 }

 async getPromise() {
  return new Promise((resolved, rejected)=> {
    resolved(1)
  });
 }

 async test() {
  let a = 2
  let c = 1
  await getConstant();
  let d = 3
  await getPromise();
  let d = 4
  await getAsyncConstant();
  return 2
 }

上面的代碼其實真正的在解析執行的時候是這樣的:

function getConstant() {
   return 1;
}

function getAsyncConstant() {
  return Promise.resolve().then(function () {
   return 1;
  });
}

function getPromise() {
  return Promise.resolve().then(function () {
   return new Promise((resolved, rejected) => {
    resolved(1);
   });
  });
}

  test() {
    return Promise.resolve().then(function () {
       let a = 2;
       let c = 1;
       return getConstant();
     }).then(function () {
       let d = 3;
       return getPromise();
     }).then(function () {
       let d = 4;
       return getAsyncConstant();
     }).then(function () {
       return 2;
     });
 }

通過上面的代碼可以看出async/await的本身還是基於Promise的。

因為await本身返回的也是一個Promise,它只是把await后面的代碼放到了await返回的Promise的.then后面,以此來實現的。

做個練習:

     function getJson(){
      return new Promise((reslove,reject) => {
        setTimeout(function(){
          console.log(2)
          reslove(2)
        },2000)
      })
     }
    async function testAsync() {
       await getJson()
       console.log(3)
    }

    testAsync()

上面的代碼是會先打印2還是3?

答案是2,3

看過上面的童鞋應該知道其實他的真實代碼是這樣的:

function getJson(){
    return new Promise((reslove,reject) => {
      setTimeout(function(){
        console.log(2)
        reslove()
      },2000)
    })
}

function testAsync() {
    return new Promise((reslove,reject) => {
        getJson().then(function (res) {
          console.log(3)
        })
    })
}

testAsync()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM