看一道面試必備的基礎(chǔ)題:異步實(shí)現(xiàn)一個(gè) sleep 函數(shù)
點(diǎn)擊上方 三分鐘學(xué)前端,關(guān)注公眾號(hào)
一、JS異步解決方案的發(fā)展歷程以及優(yōu)缺點(diǎn)
1. 回調(diào)函數(shù)(callback)
setTimeout(() => {
// callback 函數(shù)體
}, 1000)
缺點(diǎn):回調(diào)地獄,不能用 try catch 捕獲錯(cuò)誤,不能 return
回調(diào)地獄的根本問(wèn)題在于:
缺乏順序性:回調(diào)地獄導(dǎo)致的調(diào)試?yán)щy,和大腦的思維方式不符 嵌套函數(shù)存在耦合性,一旦有所改動(dòng),就會(huì)牽一發(fā)而動(dòng)全身,即(控制反轉(zhuǎn)) 嵌套函數(shù)過(guò)多的多話(huà),很難處理錯(cuò)誤
ajax('XXX1', () => {
// callback 函數(shù)體
ajax('XXX2', () => {
// callback 函數(shù)體
ajax('XXX3', () => {
// callback 函數(shù)體
})
})
})
優(yōu)點(diǎn):解決了同步的問(wèn)題(只要有一個(gè)任務(wù)耗時(shí)很長(zhǎng),后面的任務(wù)都必須排隊(duì)等著,會(huì)拖延整個(gè)程序的執(zhí)行。)
2. Promise
Promise就是為了解決callback的問(wèn)題而產(chǎn)生的。
Promise 實(shí)現(xiàn)了鏈?zhǔn)秸{(diào)用,也就是說(shuō)每次 then 后返回的都是一個(gè)全新 Promise,如果我們?cè)?then 中 return ,return 的結(jié)果會(huì)被 Promise.resolve() 包裝
優(yōu)點(diǎn):解決了回調(diào)地獄的問(wèn)題
ajax('XXX1')
.then(res => {
// 操作邏輯
return ajax('XXX2')
}).then(res => {
// 操作邏輯
return ajax('XXX3')
}).then(res => {
// 操作邏輯
})
缺點(diǎn):無(wú)法取消 Promise ,錯(cuò)誤需要通過(guò)回調(diào)函數(shù)來(lái)捕獲
3. Generator
特點(diǎn):可以控制函數(shù)的執(zhí)行,可以配合 co 函數(shù)庫(kù)使用
function *fetch() {
yield ajax('XXX1', () => {})
yield ajax('XXX2', () => {})
yield ajax('XXX3', () => {})
}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()
4. Async/await
async、await 是異步的終極解決方案
優(yōu)點(diǎn)是:代碼清晰,不用像 Promise 寫(xiě)一大堆 then 鏈,處理了回調(diào)地獄的問(wèn)題
缺點(diǎn):await 將異步代碼改造成同步代碼,如果多個(gè)異步操作沒(méi)有依賴(lài)性而使用 await 會(huì)導(dǎo)致性能上的降低。
async function test() {
// 以下代碼沒(méi)有依賴(lài)性的話(huà),完全可以使用 Promise.all 的方式
// 如果有依賴(lài)性的話(huà),其實(shí)就是解決回調(diào)地獄的例子了
await fetch('XXX1')
await fetch('XXX2')
await fetch('XXX3')
}
下面來(lái)看一個(gè)使用 await 的例子:
let a = 0
let b = async () => {
a = a + await 10
console.log('2', a) // -> '2' 10
}
b()
a++
console.log('1', a) // -> '1' 1
對(duì)于以上代碼你可能會(huì)有疑惑,讓我來(lái)解釋下原因
首先函數(shù) b先執(zhí)行,在執(zhí)行到await 10之前變量a還是 0,因?yàn)?await內(nèi)部實(shí)現(xiàn)了generator,generator會(huì)保留堆棧中東西,所以這時(shí)候a = 0被保存了下來(lái)因?yàn)? await是異步操作,后來(lái)的表達(dá)式不返回Promise的話(huà),就會(huì)包裝成Promise.reslove(返回值),然后會(huì)去執(zhí)行函數(shù)外的同步代碼同步代碼執(zhí)行完畢后開(kāi)始執(zhí)行異步代碼,將保存下來(lái)的值拿出來(lái)使用,這時(shí)候 a = 0 + 10
上述解釋中提到了 await 內(nèi)部實(shí)現(xiàn)了 generator,其實(shí) await 就是 generator 加上 Promise的語(yǔ)法糖,且內(nèi)部實(shí)現(xiàn)了自動(dòng)執(zhí)行 generator。如果你熟悉 co 的話(huà),其實(shí)自己就可以實(shí)現(xiàn)這樣的語(yǔ)法糖。
二、4 種方式實(shí)現(xiàn)一個(gè) sleep 函數(shù)
1. Promise
//Promise
const sleep = time => {
return new Promise(resolve => setTimeout(resolve,time))
}
sleep(1000).then(()=>{
console.log(1)
})
2. Generator
//Generator
function* sleepGenerator(time) {
yield new Promise(function(resolve,reject){
setTimeout(resolve,time);
})
}
sleepGenerator(1000).next().value.then(()=>{console.log(1)})
3. async await
//async
function sleep(time) {
return new Promise(resolve => setTimeout(resolve,time))
}
async function output() {
let out = await sleep(1000);
console.log(1);
return out;
}
output();
4. ES5
//ES5
function sleep(callback,time) {
if(typeof callback === 'function')
setTimeout(callback,time)
}
function output(){
console.log(1);
}
sleep(output,1000);來(lái)自:https://github.com/sisterAn/blog
