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