Promise\async\await 的簡單學習筆記

隨便查查網上的 Promise 教程,多到數不勝數,然而我仍是沒有準確理解什麼是 Promise 以及它的使用場景。因此打算本身寫一下學習心得,用來查漏補缺。目標是寫的簡單直白,便於之後查閱反思。es6

什麼是 Promise?

「Promise 是一個對象。」 對於這種解釋,我不是很滿意,畢竟在 JS 的世界中,萬物皆可對象(這句話也是流傳已久的bug,想知道具體的緣由,請查閱 null 相關的知識)。咱們經過 typeof Promise 能夠獲得 function。這進一步說明,Promise 更是一個函數。同時來複習一下:JS 中,函數是一種特殊的對象,MDN 中也叫作頭等對象(first-class)。因此,請不要簡單解釋爲 Promise 是一個對象,這有點偷懶。ajax

那麼在認識到 Promise 是一個函數後,這個函數的本質,又是什麼?答案是:構造函數。爲何這樣理解?由於咱們在使用 Promise 的時候,永遠是 new Promise() 開始的。既然是構造函數,當咱們建立一個 Promise 實例的時候,這個實例對象都有什麼內容?來看看下面的代碼:promise

var p = new Promise(function(resolve, reject){});
consoel.log(p);
// __proto__: Promise
// [[PromiseStatus]]: "pending"
// [[PromiseValue]]: undefined

console.log(p.__proto__)
// Promise {constructor: ƒ, then: ƒ, catch: ƒ, finally: ƒ, Symbol(Symbol.toStringTag): "Promise"}

複製代碼

咱們獲得的對象 p 上,這個對象也比較簡單,一共只有三個東西:proto,PromiseStatus,PromiseValue。這三個值。__proto__ 上則存在咱們熟悉的 then 等方法,這就是鏈式調用的原理——經過返回 Promise 對象,調用其原型鏈上的方法實現。其他兩個是內部變量,一個是記錄內部狀態,另外一個記錄了返回值。bash

Promise 的狀態有三種:異步

  • pending
  • fulfilled/resolved (好討厭這種名不正言不順的,一種狀態兩種表示的東西)
  • rejected

PromiseValue 記錄的返回值也很簡單。若是一個 promise 的狀態是完成(resolved)那麼,返回值就是 then(res => return res;) 裏的 res;若是是拒絕狀態,那麼則是 .catch() 裏面的。值得一提的是,Promise 實例中的狀態,永遠是肯定的,並且不可逆,也就是說一個已經 resolved 或者 rejected 的promise,不能轉化成 pending。async

爲何要有 Promise?

以前咱們說到 Promise 是一個構造函數,是從 Promise 的類型來看問題。若是從應用層面來看待,那麼 Promise 則是一套異步操做的處理機制。這種機制十分擅長解決回調地獄。來寫一個在 jQuery 時代不可避免的回調場景:函數

$.ajax({
  success: function(res) {
    if(res) {
      callAnotherFun(function(res) {
        $.ajax({
          success: secondResponse
        })
      });
    }
  }
})
複製代碼

改寫成 Promise學習

function fetch() {
  return new Promise(function(resolve) {
    $.ajax({
      success: function(res) {
        resolve(res);
      }
    })
  });
}

fetch().then(res => {
  return callAnotherFun(function(res) {
    return fetch()
  })
}).then(res => {
  secondResponse(res)
})
複製代碼

從上面的改寫能夠看出 Promise 將多層函數回調的嵌套fetch

function a() {
  b(function () {
    c(function() {
      d(function() {
        ...
      })
    })
  })
}
複製代碼

改寫成了優化

myPromise().then(res => {
  a();
  return myPromise();
}).then(res => {
  b();
  return myPromise();
}).then(res => {
  c();
  return myPromise();
}).then(red => {
  d();
})
複製代碼

這種寫法,統一了異步處理的風格,已經寫入 ES6 的標準之中。其實關於這樣的鏈式調用,咱們仍然有優化的空間,這個優化操做就引入下面要講的 async/await 的相關內容。

async\await 是什麼?

async函數返回一個 Promise 對象,可使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操做完成,再接着執行函數體內後面的語句。

咱們能夠將上一節的代碼改寫成 async/await 的形式,以下:

async function myPromise() { }
async function main() {
  await myPromise(function() {a () });
  await myPromise(function() {b () });
  await myPromise(function() {c () });
  await myPromise(function() {d () });
}

main();
複製代碼

從上圖能夠看出,async 提供了一種像同步風格同樣來編寫異步過程的代碼的方式。這裏要注意的是 await 必定是寫在 async 裏面的。顧名思義它是 async wait異步等待的意思。

異步的使用場景?

那麼結合到具體業務,咱們應該如何使用。常見的異步場景有:

  • 文件上傳
  • 圖片加載
  • 自動補全
  • 用戶事件

等等…… 下面我從一個小栗子來簡單應用下,感覺 Promise 和 async 結合的代碼的可讀性。

一個紅綠燈的例子

參考資料

pic
相關文章
相關標籤/搜索