ES2017 —— async await原理

Generator不熟悉的人,能夠先看下Generator的文檔:developer.mozilla.org/zh-CN/docs/…編程

前言

在ES2017以前,咱們要想把一段異步邏輯編程按照同步代碼的方式來編寫,須要依賴Generator,好比:瀏覽器

function getJSONFile() {
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      resolve({
        name: '大漠傳奇',
        age: 23,
      })
    }, 1000)
  })
}

function getHobby() {
  return new Promise(function(resolve, reject){
    setTimeout(function(){
      resolve({
        hobby: ['登山','旅遊','聽歌','看電影','看小說','打遊戲'],
      })
    }, 1000)
  })
}

function* gen(i) {
  let me = yield getJSONFile();
  console.log('me:', me);
  let hobby = yield getHobby();
  console.log('hobby:', hobby)
}

function co(genFn) {
  let gen = genFn();
  let res = gen.next()
  let run = (gen, res) => {
    if(!res.done){
      if(res.value&&(res.value.__proto__.constructor === Promise)){
        res.value.then((data) => {
          let res2 = gen.next(data)
          run(gen, res2);
        })
      }else{
        let res3 = gen.next(res.value);
        run(gen, res3);
      }
    }
    
  }
  run(gen, res);
}

co(gen)
複製代碼

可是,在ES2017提供了async && await以後,咱們上面這一坨代碼,就能夠用更加優雅的方式來編寫了。好比:異步

// async await
async function likeGen() {
  let me = await getJSONFile();
  console.log('me:', me);
  let hobby = await getHobby();
  console.log('hobby:', hobby);
  return 'end';
}

likeGen().then(res => {
  console.log('res:', res);
})
複製代碼

兩相對比,用async+await來編寫,最明顯的變化就是少了一個co函數,代碼量少了一些。其餘的代碼看起來跟用generator實現相差不大。 那麼爲何ES2017提供的async && await來編寫同步代碼時,代碼量少了一些,而且更方便呢?async

具體緣由咱們下面來介紹,咱們先看下async && await的功能簡介。函數

async && await功能簡介

async

async function 聲明用於定義一個返回 AsyncFunction 對象的異步函數。異步函數是指經過事件循環異步執行的函數,它會經過一個隱式的 Promise 返回其結果。可是若是你的代碼使用了異步函數,它的語法和結構會更像是標準的同步函數。ui

當調用一個 async 函數時,會返回一個 Promise 對象。當這個 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。spa

async 函數中可能會有 await 表達式,這會使 async 函數暫停執行,等待 Promise 的結果出來,而後恢復async函數的執行並返回解析值(resolved)。code

注意, await 關鍵字僅僅在 async function中有效。若是在 async function函數體外使用 await ,你只會獲得一個語法錯誤(SyntaxError)。對象

await

await 操做符用於等待一個Promise 對象。它只能在異步函數 async function 中使用。遊戲

await 表達式會暫停當前 async function 的執行,等待 Promise 處理完成。若 Promise 正常處理(fulfilled),其回調的resolve函數參數做爲 await 表達式的值,繼續執行 async function。

若 Promise 處理異常(rejected),await 表達式會把 Promise 的異常緣由拋出。

另外,若是 await 操做符後的表達式的值不是一個 Promise,則返回該值自己。

async+await VS generator

ES2017引入async和await目的就是簡化用generator來寫同步代碼時的繁瑣,下降用js來寫同步代碼的複雜程度,下降代碼量,讓語法更加簡單。

你能夠把async和await理解爲前言中前半部分用generator實現同步代碼的上層簡易語法糖。也就是瀏覽器幫咱們在js解釋器中實現了底層部分,咱們用async和await時,js解釋器就會理解爲generator+co函數(前言中實現的generator自動執行函數)。

這樣,咱們就不用去關注generator以及如何讓generator自動執行的問題了,要想寫同步代碼,只須要定義一個async函數,在async函數中用await來等待異步代碼的執行成功。即簡單又方便,代碼量還少。

相關文章
相關標籤/搜索