什麼是 Promise ?
Promise 就是承諾,承諾過一段時間會給你個結果(承諾來解救 Callback Hell 的)。
什麼是 Callback 呢? 如果只有一個 Callback 很好用,那就是執行完成後的下一件事,但是...
(經歷過的就知道,下面的代碼讓我想關掉電腦) 猜猜看現在執行到哪裡了呢? XD
// Callback Hell
a(function(resultA) {
b(function(resultB) {
c(function(resultC) {
d(function(resultD) {
console.log(resultD);
})
})
})
})
Callback通常會伴隨著幾種問題,包含:
1.多重的 Callback 導致 Callback Hell,也導致程式碼不直觀
2.Callback 存在著 控制權移轉 (Inversion of Control) 的問題,意思就是當一個函數移轉到另外一個函數時,有時候會出現非預期的狀況。
3.如果不寫 Error Callback 處理函數,異常就會抓不到了
註:Callback Hell 在大部分的程式語言比較少會遇到這樣的問題,主要是因為他們以同步的機制為主,但在大量使用異步的 Javascript 中我們就需要解決這項問題。
那 Promise 怎麼解決些問題?
Promise 的經典在於 狀態 ,用維護狀態、傳遞狀態的方式使得回調函數能夠即時調用,也使得異步函數可以同步化。
Promise 是一個構造函數,用來生成 Promise 實例
Promise 共有三種狀態,包含: pending(進行中)、fulfilled(已成功)、rejected(已失敗),而 Promise 的狀態是來自於異步操作,只有異步操作的結果可以決定是哪一種狀態,其他操作無法去更動這個狀態,在狀態改變後就不會在變了,有可能是從 pending 到 fulfilled
(事件成功) 或是 從 pending 到 rejected
(事件失敗),也就在這個時候狀態就終止了。
Promise 有兩個參數:
從 pending 到 fulfilled
時調用,將異步的結果作為參數傳遞出去從 pending 到 rejected
時調用,將異步的結果作為參數傳遞出去let state = 1;
function step1 (resolve, reject) {
console.log('Do the laundry');
if (state == 1) {
resolve('Do the laundry - Finish');
} else {
reject('Do the taundry - Fail');
}
}
function step2 (resolve, reject) {
console.log('Dry the clothes');
state = 2;
if (state == 1) {
resolve('Dry the clothes - Finish');
} else {
reject('Dry the clothes - Fail');
}
}
function afterStep2Pass(resolve, reject) {
resolve('pass');
}
function stepCatch (resolve, reject) {
console.log('The machine is broken');
if (state != 1) {
resolve('Fix the machine');
}
}
new Promise(step1).then(val => {
console.log(val);
return new Promise(step2)
}).then(val => {
return new Promise(afterStep2Pass); // 因為 step2 reject,這一段會被跳過
}).catch(val => {
console.log(val);
return new Promise(stepCatch);
}).then(val => {
console.log(val);
return val;
}).finally(() => {
console.log('done');
})
// Do the laundry, Do the laundry - Finish, Dry the clothes, Dry the clothes - Fail, The machine is broken, Fix the machine, done
上面的例子是以清潔衣服為例子,要完成洗衣服這項動作需要經過:洗衣服、烘乾衣服,要保證上一步完成,才能進行到下一步,如果中間出問題了,像是機器壞掉就會送 catch,當然也因此 step2 後面的 then 就直接被跳過了。如果以ES6之前可能要兩層 Callback,上方是改寫為 Promise 的方式。
執行順序是 step1->step2-(因改state,reject前往 catch)->stepCatch->finally
。
then 方法是作為 Promise 改變狀態後的 Callback,
onFulfilled[, onRejected]
,then 第一個參數是 fulfilled 狀態的 Callback,第二個參數是 rejected 狀態的 Callback
var p1 = new Promise( (resolve, reject) => {
resolve('Success!');
// or
// reject ("Error!");
} );
p1.then( value => {
console.log(value); // Success!
}, reason => {
console.log(reason); // Error!
} );
catch 方法是
then(null, rejection) 或 then(undefined, rejection)
的別稱,用於 Promise 發生錯誤時的 allback。
finally 方法用於不管 Promise 最後的狀態如何,這操作都會執行
多個 Promise 行為同時執行,全部完成後統一回傳
const p = Promise.all([p1, p2, p3]);
如果 p1, p2, p3 狀態都變成 fulfilled,p 的狀態才會是 fulfilled,這時候返回 [p1, p2, p3]的陣列結果給 p。
多個 Promise 同時執行,但僅回傳第一個完成的
執行方式跟 Promise.all()
一樣,唯一不同的是執行完後它只返回單一結果
,為第一個運行完成的,以上方Promise.all 的例子也就是 p1。
Promise 在建立後就會立刻執行,無法(中途)取消 Promise,如果不設置 Callback,Promise 內部拋錯就不會反應到外部。如果處於 pending 狀態時,無法知道現在到哪個階段了。