簡單聊聊ES6-Promise和Async

pubdreamcc發表於2019-05-23

前言

本篇博文出至於我的github倉庫:web-study,如果你覺得對你有幫助歡迎star,你們的點贊是我持續更新的動力,謝謝!

非同步程式設計在前端開發中尤為常見,從最早的XHR,到後來的各種封裝ajax,再到DOM事件觸發的回撥,無不涉及非同步程式設計。今天我們們來聊聊ES6中新提出的非同步解決方案:Promiseasync/await

  • Promise的原理和基本用法
  1. Promise的原理

Promise 是一種對非同步操作的封裝,可以通過獨立的介面新增在非同步操作執行成功、失敗時執行的方法。主流的規範是 Promises/A+。

Promise中有幾個狀態:

  * pending: 初始狀態, 非 fulfilled 或 rejected;

  * fulfilled: 成功的操作,為表述方便,fulfilled 使用 resolved 代替;

  * rejected: 失敗的操作。

node演示

pending可以轉化為fulfilled或rejected並且只能轉化一次,也就是說如果pending轉化到fulfilled狀態,那麼就不能再轉化到rejected。並且fulfilled和rejected狀態只能由pending轉化而來,兩者之間不能互相轉換。

  1. Promise的基本用法

Promise是一個建構函式,自己身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等同樣很眼熟的方法。

  • resolve的用法

    var p = new Promise(function(resolve, reject){
      //做一些非同步操作
      setTimeout(function(){
          resolve('隨便什麼資料');
      }, 2000);
    })
    p.then(res => {
      console.log(res) // '隨便什麼資料'
    })

Promise的建構函式接收一個引數,是函式,並且傳入兩個引數:resolve,reject,分別表示非同步操作執行成功後的回撥函式和非同步操作執行失敗後的回撥函式。其實這裡用“成功”和“失敗”來描述並不準確,按照標準來講,resolve是將Promise的狀態置為fullfiled,reject是將Promise的狀態置為rejected。

在上面的程式碼中,我們執行了一個非同步操作,也就是setTimeout,2秒後,並且呼叫resolve方法,表示非同步操作執行成功。

  • reject的用法

javascript var p = new Promise(function(resolve, reject){ //做一些非同步操作 setTimeout(function(){ reject('隨便什麼資料'); }, 2000); }) p.catch(err => { console.log(err) // '隨便什麼資料' })

上面我們在非同步操作中呼叫了reject方法,也就是說把Promise的狀態由pending轉換到了fulfilled狀態,最後可以通過Promise例項物件的catch()方法獲取非同步資料。

  • Async/Await簡介與用法

非同步操作是 JavaScript 程式設計的麻煩事,很多人認為async函式是非同步操作的終極解決方案。

  1. Async/Await簡介
  • async/await是寫非同步程式碼的新方式,優於回撥函式和Promise。

  • async/await是基於Promise實現的,它不能用於普通的回撥函式。

  • async/await與Promise一樣,是非阻塞的。

  • async/await使得非同步程式碼看起來像同步程式碼,再也沒有回撥函式。但是改變不了JS單執行緒、非同步的本質。

  1. Async/Await的用法
  • 使用await,函式必須用async標識

  • await後面跟的是一個Promise例項或者是其他的任意js表示式(意義不大)


var fun = async () => {
  let result = await Promise.resolve(123)
  console.log(result)
}
fun() // 123

await等待的雖然是promise物件,但是不用呼叫.then()方法就能直接得到返回值。

  1. Async/Await的應用

Promise雖然一方面解決了callback的回撥地獄,但是相對的把回撥“縱向發展”了,形成了一個回撥鏈。example:

function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait)
        },wait)
    })
}

/*
let p1 = sleep(100)
let p2 = sleep(200)
let p =*/

sleep(100).then(result => {
    return sleep(result + 100)
}).then(result02 => {
    return sleep(result02 + 100)
}).then(result03 => {
    console.log(result03)
})

控制檯輸出:
300
後面的結果都是依賴前面的結果。

改成async/await寫法就是:

async function demo() {
    let result01 = await sleep(100)
    //上一個await執行之後才會執行下一句
    let result02 = await sleep(result01 + 100)
    let result03 = await sleep(result02 + 100)
    // console.log(result03);
    return result03
}

demo().then(result => {
    console.log(result)
})

因為async返回的也是promise物件,所以用then接受就行了。

結果:
300

需要注意的就是 await是強制把非同步變成了同步,這一句程式碼執行完,才會執行下一句。

相關文章