ES6入門之Promise對象

1. Promise 的含義

Promise 是異步編程的一種解決方案,比傳統的解決方案--回調函數和事件更合理、更強大。編程

1.1 什麼是Promise

簡單來講就是一個容器,裏面保存着某個將來纔會結束的事件(也就是異步操做)的結果。從語法上來說,Promise是一個對象,從它能夠獲取異步操做的消息,它提供統一的API,各類異步操做均可以用一樣的方法進行處理。數組

Promise有兩個特色:

1.1.一、對象的狀態不受外界影響。Promise對象表明一個異步操做,有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態、任何其餘操做都沒法改版這個狀態。promise

1.1.二、一旦狀態改版,就不會再變,任什麼時候候均可以獲得這個結果。Promise對象的狀態改變,只存在兩種可能:從 pending 變爲 fulfilled 和 從 pending 變爲 rejeced。只要這兩種狀況發生,狀態就終止,不會再變了並一直保持這個結果。這時就稱爲 resolved(已定型)。若是改版已經發生了,即便再對Promise對象添加回調函數,也會當即獲得這個結果。若是你錯過了再想去監聽,是得不到結果的。bash

1.1.三、有了Promise對象,就能夠將異步操做以同步操做的流程顯示出來,這樣就避免了層層嵌套的回調函數。Promise對象提供統一的接口,使得控制異步操做更加容易。異步

1.1.四、Promise也有一些缺點,就是沒法取消 Promise,一旦創建就會當即執行,沒法中途取消。若是不設置回調函數,Promise內部拋出的錯誤不會反應到外部。另外若是處於 pending 狀態時,是沒法知道如今到了哪個階段。異步編程

2. 基本用法

Promise對象是一個構造函數,用來生成Promise實例函數

const promise = new Promise((reolve, reject) => {
    if (// 異步操做成功) {
        resolve(val)
    }else{
        reject(val)
    }
})
複製代碼

Promise 構造函數接受一個函數做爲參數,該函數的兩個參數分別是 resolve 和 reject。ui

resolve:,將Promise對象的狀態從『未完成』變爲『成功』(pending => resolved),在異步操做成功時調用,並將異步操做的結果做爲參數傳遞出去。spa

reject:將Promise對象的狀態從『未完成』變爲『失敗』(pending => rejected),在異步操做失敗時調用,並將異步操做的結果做爲參數傳遞出去。prototype

Promise 實例生成之後,能夠用 then 方法分別指定 resolved 狀態和 rejected 狀態的回調函數。

promise.then((val) => {
    // success
},(err) => {
    // failure
})
複製代碼

then方法能夠接受兩個回調函數做爲參數。(第二個函數可選,這兩個函數都接受Promise對象傳出的值做爲參數)

一、第一個回調函數在Promise對象的狀態變爲『resolved』時調用。

二、第二個回調函數在Promise對象的狀態變爲『rejected』時調用。

實例:

function timeout(ms) {
    retrun new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done')
    })
}

timeout(100)
.then((v) => {
    console.log(v)
})
複製代碼

上面代碼中,timeout方法返回一個Promise實例,表示一段時間之後纔會發生的結果,過了 ms時間後,Promise狀態變爲『resolved』而後就會觸發then方法綁定的回調函數。

Promise 創建後就會當即執行

let promise = new Promise((resolve, reject) => {
    console.log('Promise')
    resolve()
})

promise
.then(() => {
    console.log('resolved')
})

console.log('hh')

// Promise
// hh
// resolved
複製代碼

Promise創建後當即執行,首先輸出 「Promise」而後執行promise 的then函數,而後首先執行同步任務 輸出 hh 在執行 then方法的回調函數輸出resolved

若是調用 resolve 函數和 reject 函數時帶有參數,那麼它們的參數會被傳遞給回調函數。reject函數的參數一般是Error對象的實例,表示拋出的錯誤。resolve函數的參數除了正常的值之外,還有多是一個Promise實例。resolve實在成功的時候調用,reject是在失敗的時候調用。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})
複製代碼

上述代碼中:p1 和 p2都是Promise的實例,可是p2的 resolve方法將 p1做爲參數,即一個異步操做的結果返回是另外一個異步操做。

注意:p1的狀態就會傳遞給p2,p1的狀態決定了p2的狀態。若是p1的狀態是pending,那麼p2的回調函數就會等待p1的狀態改變;若是p1的狀態已是 resolved 或者 rejected,那麼p2的回調函數會當即執行。

通常來講,調用resolve 或 reject之後,Promise的進程就就結束了,後續操做應該放到 then方法裏,而不是直接寫在 resolve 或 reject 的後面。另外最後在它們以前加上 return語句。

3. Promise.prototype.then()

Promise實例具備 then 方法,then方法是定義在原型對象 Promise.prototype上的。它的做用是爲 Promise 實例添加狀態改變時的回調函數。then 的第一個參數是 resolved狀態的回調函數,第二個參數是 rejected狀態的回調函數。

then方法返回的是一個新的 Promise 實例,不是原來那個,所以可使用鏈式寫法。.then().then()

a().then((j) => {
    retrun j
}).then((i) => {
    console.log(i)
},(err)=>{
    console.log(err)
})
複製代碼

上面 第一個then方法指定的回調函數,返回的是另外一個 Promise 對象。這時,第二個 then 方法指定的回調函數,就會等這個新的 Promise對象狀態發生變化,若是變爲 resolved,就調用第一個回調函數,若是狀態變爲 rejected,就調用第二個回調函數。

4. Promise.prototype.catch()

Promise.prototype.catch 方法是 .then(null, rejecton) 或 .then(undefined, rejection)的別名,用於指定發生錯誤時的回調函數。

a().then((p) => {
    // success
}).catch((err) => {
    console.log('err')
})
複製代碼

若是對象的狀態變爲 resolved, 則會調用 then 方法指定的回調函數 success,若是異步操做拋出錯誤,狀態就會變爲 rejected,就會調用 catch 方法指定的回調函數處理這個錯誤。若是 then 方法指定的回調函數,在運行中拋出錯誤,也會被catch 方法捕獲。

另外reject方法的做用等同於拋出錯誤

若是 Promise狀態已經變成 resolved,再拋出錯誤是無效的。由於狀態一旦改版,就永遠保持,不會再變了。 並且Promise的錯誤有『冒泡』的性質,會一直向後傳遞,直到被捕獲位置,它的錯誤總會被下一個catch語句捕獲

建議:Promise 對象後面要跟catch方法,這樣能夠處理 Promise 內部發生的錯誤。catch方法返回的仍是一個 Promise 對象,所以後面還能夠接着調用then方法。

注意: catch函數中的方法發生錯誤,若是後面沒有別的catch 方法,那麼錯誤將不會被捕獲,若是 catch 後面 還有catch ,第二個catch將會捕獲前一個catch方法拋出的錯誤。

5. Promise.prototype.finally()

finally 方法用於指定無論 Promise 對象最後狀態如何,都會執行的操做。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
複製代碼

以上,無論promise 最後的狀態,都會執行 finally 方法指定的函數。

finally 方法的回調函數不接受任何參數,因此就沒法知道以前Promise狀態究竟是 fulfilled 仍是 rejected。因此在finally方法裏面的操做,是與以前狀態無關的並且不依賴於Promise的執行結果。

6. Promise.all()

Promise.all 方法用於將多個 Promise 實例,包裝成一個新的 Promise實例。

const p = Promise.all([p1, p2, p3])
複製代碼

Promise.all 方法接受一個數組做爲參數,p一、p二、p3都是Promise實例,若是不是,就會先調用Promise.resolve方法,將參數轉爲 Promise 實例再處理。(Promise.all 方法的參數能夠不是數組,但必須具備 Iterator 接口,且返回的每一個成員都是 Promise 實例。)

Promise.all 的狀態有兩種狀況:

一、若是 p1 p2 p3的狀態都變成了 fulfilled,p的狀態纔是fulfilled,這時候返回一個 p1 p2 p3返回值組成的數組,傳遞給 p 的回調函數。

二、若是 p1 p2 p3中任一一個被rejected,p 的狀態就變成了 rejected,這時候返回的是第一個被 rejected 實例的返回值,傳遞給 p 的回調函數。

注意,若是做爲參數的 Promise 實例,本身定義了catch方法,那麼它一旦被rejected,並不會觸發Promise.all()的catch方法。而是觸發本身定義的catch方法。

7. Promise.race()

Promise.race方法一樣是將多個 Promise 實例,包裝成一個新的 Promise實例。

const p = Promise.race([p1, p2, p3]);
複製代碼

與 Promise.all 的區別就是 p1 p2 p3 中一個實例改變狀態,那麼 p 的狀態就跟着改變了,返回值爲最早返回那個Promise實例的返回值。

8. Promise.resolve()

將現有對象轉爲 Promise 對象。

一、若是參數是一個Promise 實例
那麼將不作任何修改。
複製代碼
二、參數是一個 thenable對象(具備then方法的對象)
將這個對象轉爲Promise對象,而後當即執行 thenable對象的then方法
複製代碼
三、參數不是具備then方法的對象,或根本不是對象
返回一個新的Promise對象,狀態爲 resolved
複製代碼
四、不帶任何參數
直接返回一個 resolved 狀態的Promise對象
複製代碼

9. Promise.reject()

Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態爲rejected。回調函數當即執行。

關注公衆號 【小夭同窗】

公衆號小夭同窗
相關文章
相關標籤/搜索