JavaScript 中常見的異步函數有:定時器,事件和ajax等,那麼如何來處理這些異步函數呢,常用的方法有下面幾種:
1. 回調函數
function eat() {
console.log('好的,我開動咯');
}
function cooking(cb) {
console.log('媽媽認真做飯');
setTimeout(function () {
console.log('小明快過來,開飯啦')
cb();
}, 1000);
}
function read() {
console.log('小明假裝正在讀書');
}
cooking(eat);
read();
/* 執行順序:
媽媽認真做飯
小明假裝正在讀書
小明快過來,開飯啦
好的,我開動咯
*/
優點: 簡單
缺點: 如果有大量異步並存在依賴會形成回調地獄
2. 事件
function eat() {
console.log('媽媽敲門啦,該去吃飯啦');
}
function cooking() {
console.log('媽媽認真做飯');
setTimeout(function () {
console.log('小明,出來吃飯啦')
bus.$emit('done');
}, 3000);
}
function read() {
console.log('小明又假裝正在讀書');
bus.$on('done', eat);
}
cooking();
read();
/* 執行順序:
媽媽認真做飯
小明又假裝正在讀書
小明,出來吃飯啦
媽媽敲門啦,該去吃飯啦
*/
優點:代碼解耦
缺點:處理回調地獄需要定義和監聽大量的事件
3. 發佈訂閱
function eat() {
console.log('爸爸叫我去吃飯啦');
}
function cooking() {
console.log('媽媽認真做飯');
setTimeout(function () {
console.log('孩子他爸,叫小明出來吃飯');
Dad.publish("done");
}, 3000);
}
function read() {
console.log('小明依舊假裝正在讀書');
Dad.subscribe('done', eat);
}
cooking();
read();
/* 執行順序:
媽媽認真做飯
小明依舊假裝正在讀書
孩子他爸,叫小明出來吃飯
爸爸叫我去吃飯啦
*/
優點:創建了一下中介者(Dad)來管理髮布和訂閱,事件越多越強大
缺點:仍然需要定義一大堆事件
4. promise
function read() {
console.log('小明認真讀書');
}
function eat() {
return new Promise((resolve, reject) => {
console.log('好嘞,吃飯咯');
setTimeout(() => {
resolve('飯吃飽啦');
}, 1000)
})
}
function wash() {
return new Promise((resolve, reject) => {
console.log('唉,又要洗碗');
setTimeout(() => {
resolve('碗洗完啦');
}, 1000)
})
}
function mop() {
return new Promise((resolve, reject) => {
console.log('唉,還要拖地');
setTimeout(() => {
resolve('地拖完啦');
}, 1000)
})
}
const cooking = new Promise((resolve, reject) => {
console.log('媽媽認真做飯');
setTimeout(() => {
resolve('小明快過來,開飯啦');
}, 3000);
})
cooking.then(msg => {
console.log(msg);
return eat();
}).then(msg => {
console.log(msg);
return wash();
}).then(msg => {
console.log(msg);
return mop();
}).then(msg => {
console.log(msg);
console.log('終於結束啦,出去玩咯')
})
read();
/* 執行順序:
媽媽認真做飯
小明認真讀書
小明快過來,開飯啦
好嘞,吃飯咯
飯吃飽啦
唉,又要洗碗
碗洗完啦
唉,還要拖地
地拖完啦
終於結束啦,出去玩咯
*/
優點: 既有回調函數的簡單直觀,又具備事件的狀態內聚
缺點: 錯誤會被吃掉,無法通過window.onerror捕獲
參考:
https://github.com/frontend9/fe9-library/issues/14
https://github.com/mqyqingfeng/Blog/issues/98