網(wǎng)站維護工作是做啥web網(wǎng)頁制作成品
目錄
- 前言
- 一、執(zhí)行器函數(shù)的執(zhí)行順序
- 二、如何在then()中拋出錯誤
- 三、期約的"非重入"特性
- 四、串行化期約
- 五、應(yīng)對回調(diào)地獄
- 結(jié)語
前言
依據(jù)《JavaScript高級程序設(shè)計》對Promise期約相關(guān)進行查缺補漏.
一、執(zhí)行器函數(shù)的執(zhí)行順序
執(zhí)行器函數(shù)雖作為期約的參數(shù), 卻是期約的初始化程序在同步隊列中執(zhí)行, 即程序從上到下執(zhí)行下來碰到期約, 會先在同步任務(wù)隊列執(zhí)行完執(zhí)行器函數(shù)再進去期約.
ECMAScript暴露的異步結(jié)構(gòu)中, 任何對象都有then方法, 而有實現(xiàn)了該方法的結(jié)構(gòu)即被認(rèn)為實現(xiàn)了thenable接口. Promise
的原型上也實現(xiàn)了then()
方法:
new Promise((resolve, reject) => {
...
}).then();
then()
只接受函數(shù)類型參數(shù)且最多2個.
二、如何在then()中拋出錯誤
then(()=>{throw 'baz';
});
then(()=>{Error('qux');
})
兩種都正確,前者拋出報錯;
后者返回一個包裝于Promise對象中的錯誤對象可以反應(yīng)調(diào)用棧情況, 以正常值輸出.
三、期約的"非重入"特性
期約"落定"后, 處理程序(即then的參數(shù)函數(shù)onResolved
和onRejected
)僅會加入排期而非立即執(zhí)行, 而排在處理程序后的同步語句會先執(zhí)行, 此特性是由Javascript運行時保證的,即then內(nèi)部語句的輸出會晚于then外部更加靠后的語句的輸出.
其原因為在一個落定期約上調(diào)用then雖會把then中的處理程序推進消息隊列, 但在當(dāng)前線程上的同步代碼執(zhí)行完成前處理程序依然不會被執(zhí)行. 更符合常理一些的寫法, 對一個已寫入處理程序的期約落定后, 也會是這樣的輸出順序.
四、串行化期約
期約連鎖: then()
內(nèi)再構(gòu)建期約, 串行化異步任務(wù)即:
new Promise((resolve, reject) => { console.log ('P1 executor'); setTimeout (resolve, 1000);
})
.then (() => { new Promise((resolve, reject) => { console.log('P2 executor'); setTimeout(resolve, 1000);
})
.then(() => {new Promise((resolve, reject) => { console.log('P3 executor'); setTimeout(resolve, 1000);
});
但書中似乎認(rèn)為這種串行式結(jié)構(gòu)并未解決回調(diào)地獄(未明確表明).
五、應(yīng)對回調(diào)地獄
可見第四節(jié)這種串行結(jié)構(gòu)有同質(zhì)部分,如果將同質(zhì)部分使用工廠函數(shù)調(diào)用生產(chǎn),這種結(jié)構(gòu)可以演化為:
function delayedResolve(str) {return new Promise((resolve, reject) => { console.log(str);setTimeout (resolve, 1000);});
} //工廠函數(shù)delayResolve('P1 executor').then(() => { delayResolve('P2 executor');
})
.then(()=> {delayResolve('P3 executor')
})
每次調(diào)用"生產(chǎn)"返回一塊期約對象同質(zhì)部分,返回后相當(dāng)于回到了期約串行結(jié)構(gòu):
new Promise().then(() => {delayResolve();
}).then()
上例期約體同質(zhì)部分只分為一種,打比方如果上例有一段串行塊的期約內(nèi)還輸出了1,這就是另一種同質(zhì)部分,就要再單獨為這段輸出了1的期約構(gòu)建工廠函數(shù).
以上為基礎(chǔ),如果不使用期約,以回調(diào)函數(shù)形式喚起后續(xù)的異步操作就會是這樣:
function delayedExecute(str, callback = null) { setTimeout(() => { callback && callback();}, 1000)
}delayedExecute('P1callback', () => {delayedExecute('P2callback', () => {delayedExecute('P3callback', () => { delayedExecute('P4callback');});});
});
《JavaScript高級程序設(shè)計》中稱這樣的一種結(jié)構(gòu), 破除了回調(diào)地獄.
那么這種結(jié)構(gòu)到實戰(zhàn)中,加上ajax請求就不能再每次傳一個字面量,因為我們要模仿回調(diào)地獄里下個參數(shù)為上個結(jié)果的情況,就要把上次請求的結(jié)果傳到下個回調(diào)函數(shù)內(nèi):
function delayedExecute(params, callback = null) { $.ajax({url: 'xx/xx',type:'post',data: { a: params.a, b: params.b },success (res) { callback && callback(res);}
})
}delayedExecute(data0, (res0) => {delayedExecute(res0, (res1) => {delayedExecute(res1, (res2) => { delayedExecute(res2);});});
});
結(jié)語
如有疏漏,請為我指正,謝謝.