Promise 用法解析

shohan發表於2019-06-21

  • Promise 用一句話來概括就是:
  • Promise 物件用於表示一個非同步操作的最終狀態(完成或失敗),以及該非同步操作的結果值。
  • 一般通過 new 來例項化它
  • 接收一個建構函式有並帶兩個函式引數,分別表示成功或失敗時的輸出

    這是一個簡單的應用場景

    
    function promise1() {
    return new Promise((resolve, reject) => {
        //這裡模擬非同步動作,一般來說可以放置Ajax請求, 'promise1-result'為請求成功後的返回結果
        //注:Promise例項只能通過resolve 或 reject 函式來返回,並用then()或者catch()獲取
        //不能在裡面直接return ... 這樣是獲取不到Promise返回值的
        setTimeout(() => resolve('promise1-result'), 1000)
    })
    }

promise1()
.then(response => console.log(response)) //這裡可以看到列印出了resolve()的結果
.catch(error => console.log(error)) //如果狀態為rejected或出現編譯錯誤則在這一步列印

* 上面的語法使用了ES6語法
* 如果用ES5語法重寫一遍是這樣的,在支援這兩種語法的編譯器上效果都是一樣的,Es6的語法更簡潔

function promise1() {
return new Promise(function(resolve, reject){
setTimeout(function() {
resolve('promise1-result')
}, 1000)
})
}
promise1()
.then(function(response){
console.log(response)
})
.catch(function(error){
console.log(error)
})

* 相比較下,會發現ES6的語法真的簡潔太多
***
## 下面來詳細說明一下Promise的語法
* new Promise( function(resolve, reject) {...} /* executor */ );
* Promise例項化時帶有一個建構函式 executor,並接收 resolve 和 reject 兩個引數的函式
* Promise建構函式執行時立即呼叫executor函式,並將 resolve 和 reject 兩個函式作為引數傳遞給executor
* resolve 和 reject 函式被呼叫時,分別將Promise的狀態改為fulfilled(完成) 或rejected(失敗)
* 也就是說,executor 內部通常會執行一些非同步操作,一旦非同步操作執行完畢(可能成功/失敗)
* 要麼呼叫resolve函式來將Promise狀態改成fulfilled
* 要麼呼叫reject函式來將Promise狀態改為rejected
* 如果在executor函式中丟擲一個錯誤,即使沒有呼叫reject,該Promise的狀態也改為rejected

### 上面的例項場景中如果要體現resolve或reject, 我們這樣寫

function promise1() {
return new Promise((resolve, reject) => {
var result = '';
setTimeout(() => {
var result = 'async-result' //這裡只是模擬資料,真實情況是非同步獲取資料
if(!result) {
reject('no result') //如果結果為空則更改狀態為rejected並返回字元'no result'
} else {
resolve(result) //如果拿到結果則更改狀態為fulfilled並返回 result
}
}, 1000)
})
}

***
## 下面來細說一下Promise的方法
**Promise.all() .race() .resolve() .reject() .then() .catch() .finally()**
***
1. Promise.all(iterable)
* 這個方法返回一個新的Promise物件,常被用於處理多個Promise物件的狀態集合
* 該物件在iterable引數物件裡所有的Promise物件都成功時才觸發成功
* 一旦有任何一個iterable裡面的Promise物件失敗則立即觸發該Promise物件的失敗
* 這個新的Promise物件在觸發成功狀態後,會把一個包含iterable裡所有Promise返回值的陣列作為成功回撥的返回值 
* 如果觸發了失敗狀態,則會把iterable裡第一個觸發失敗的promise物件的錯誤資訊作為它的失敗錯誤資訊
* 下面就用例項來演示說明:

const getRandom = () => (Math.random()*1000).toFixed(0);
//taskID為執行非同步操作的任務ID
const asncyTask = (taskID) => new Promise( (resolve, reject) => {
let timeout = getRandom();//這裡模擬非同步請求時間0~1000毫秒
//列印出是哪一個任務ID在執行,還有一個簡潔的寫法 console.log(taskID=${taskID} start.)
console.log('taskID=' + taskID + '---start.')
//模擬非同步執行
setTimeout(() => {
console.log(taskID=${taskID} finished in time=${timeout}.)
resolve(taskID) //執行成功返回執行的ID
}, timeout)
})

Promise.all([asncyTask(1), asncyTask(2), asncyTask(3)])
.then(resultList => console.log('resultList: ', resultList)) //列印返回的結果陣列
.catch(error => console.log(error))
//上面的例項的執行結果列印出來如下:
taskID=1---start.
taskID=2---start.
taskID=3---start.
taskID=1 finished in time=109.
taskID=2 finished in time=790.
taskID=3 finished in time=840.
resultList: (3) [1, 2, 3]
//可以看到所有的非同步執行按照傳入的陣列順序一一執行並返回陣列結果了

***
2. Promise.race(iterable) 
* 當iterable引數裡的任意一個子Promise被成功或失敗後,
* 父Promise馬上也會用子Promise的成功值或失敗詳情作為引數呼叫父Promise繫結的相應控制程式碼,並返回該Promise物件
* 上面的解釋很抽象也不太容易明白
* 其實,語法和all()一樣,不同的是處理的邏輯不一樣,
* race()只要根據傳入的多個Promise例項中的任意一個例項有resolve或reject, 那就直接返回該結果,其它例項不再執行
* 下面還是通過一個例項來演示說明:

Promise.race([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise((resolve, reject) => setTimeout(() => resolve(2), 600)),
new Promise((resolve, reject) => setTimeout(() => resolve(3), 300))
]).then(responseValue => console.log(responseValue))
//執行這段指令碼後可以看到列印的結果是 3 ,因為第三個子Promise例項中的非同步最先執行完成 300毫秒
//這個操作應用場景可以用於請求多個不同的伺服器根據請求速度最先獲取資料資源


***
3. Promise.resolve(value)
* 返回的Promise物件狀態為fulfilled, 並且將該value傳遞給對應的then()方法
* 例項上面有,就不做解釋了

***
4. Promise.reject(reason)
* 返回一個狀態為失敗(rejected)的Promise物件,並將給定的失敗資訊傳遞給對應的處理方法(catch())

***
### 下面三個是原型方法
5. Promise.prototype.then(onFulfilled, onRejected)
* 新增成功(fulfilled)或失敗(rejected)回撥到當前Promise,返回一個新的Promise,將以回撥的返回值來resolve
* 應用時是用一個實現的Promise物件的例項來引用它,如 PromiseObj.then(responseValue)

6. Promise.prototype.catch(onRejected)
* 新增一個失敗回撥到當前Promise, 返回一個新的Promise,並以回撥的返回值來resolve
* 應用時是用一個實現的Promise物件的例項來引用它,如 PromiseObj.then(responseValue).catch(reasonError)

7. Promise.prototype.finally(onFinally)
* 新增一個事件處理回撥到當前Promise物件, 回撥會在當前Promise執行完畢後被呼叫
* 無論當前Promise的狀態是完成還是失敗
* 如 PromiseObj.then(responseValue).catch(reasonError).finally(callback)
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章