Promises(承諾)是JavaScript中處理異步操作的一種機制,它提供了一種更優(yōu)雅和可讀性更高的方式來處理異步代碼。Promises的實現(xiàn)原理基于一種稱為"Promise/A+"規(guī)范的約定,該規(guī)范定義了Promises的行為和接口。
Promises的實現(xiàn)原理是什么?
Promises的實現(xiàn)原理可以通過以下4步概括:
- Promise有3種狀態(tài):pending、fulfilled和rejected。初始狀態(tài)為pending。
- Promise實例包含一個then方法,then方法接受兩個參數(shù):onFulfilled和onRejected,分別為promise成功或失敗的回調(diào)。
- Promise有一個內(nèi)部屬性[[PromiseState]],初始值為pending。內(nèi)部又有一個屬性[[PromiseResult]],初始值為undefined。
- Promise的狀態(tài)只能從pending到fulfilled或rejected,狀態(tài)一旦改變就不能再變。 fulfilled和rejected狀態(tài)都會觸發(fā)then里的回調(diào)。
當(dāng)我們new一個Promise時,會傳入一個執(zhí)行器executor,執(zhí)行器會立即執(zhí)行。在執(zhí)行器中我們可以處理異步任務(wù),比如發(fā)送ajax請求,一旦異步任務(wù)執(zhí)行結(jié)束,就可以決定是resolve(成功)還是reject(失敗)這個promise。
如果執(zhí)行resolve,那么將[[PromiseState]]設(shè)為fulfilled,[[PromiseResult]]設(shè)為傳入的值。執(zhí)行onFulfilled回調(diào)。
如果執(zhí)行reject,那么將[[PromiseState]]設(shè)為rejected,[[PromiseResult]]設(shè)為傳入的reason。執(zhí)行onRejected回調(diào)。
這樣通過狀態(tài)和結(jié)果的改變,來觸發(fā)then里不同的回調(diào),從而實現(xiàn)異步流程的控制。
Promise就是通過狀態(tài)改變來觸發(fā)回調(diào)的,這也是它實現(xiàn)異步編程的基石。
如果在Promise的執(zhí)行器函數(shù)(executor)中不調(diào)用resolve或reject, 會怎么樣?
如果在Promise的執(zhí)行器函數(shù)(executor)中不調(diào)用resolve或reject,通常會導(dǎo)致兩個結(jié)果:
- Promise對象的狀態(tài)永遠保持pending
Promise對象代表一個異步操作,它的最終狀態(tài)應(yīng)該在某個時刻確定下來(fulfilled或rejected)。如果executor函數(shù)中不調(diào)用resolve或reject,Promise的狀態(tài)就無法得以確定,會永遠處于pending狀態(tài)。
- then方法指定的回調(diào)函數(shù)不會被調(diào)用
then方法注冊的回調(diào)函只有在Promise狀態(tài)確定后才會被調(diào)用,如果狀態(tài)一直是pending,那么then方法的回調(diào)函數(shù)就永遠不會被執(zhí)行。
所以,如果在executor函數(shù)中不調(diào)用resolve或reject,就是一個錯誤的實現(xiàn),違反了Promise/A+規(guī)范。
正確的做法是,在executor函數(shù)中,無論異步任務(wù)是否成功,都需要在最后調(diào)用resolve或者reject,將Promise的狀態(tài)確定下來,以便觸發(fā)then方法注冊的回調(diào)。通常like這樣:
new Promise((resolve, reject) => {
// ...做一些異步操作
if(成功) {
resolve(value);
} else {
reject(error);
}
})
所以,不調(diào)用resolve/reject,將導(dǎo)致Promise永遠pending,然后注冊的回調(diào)函數(shù)也就不會執(zhí)行。這違反Promise的設(shè)計初衷,應(yīng)該避免這樣使用。