衆所周知 JavaScript 是單線程(single thread)工作,也就是隻有一個腳本執行完成後才能執行下一個腳本,兩個腳本不能同時執行,如果某個腳本耗時很長,後面的腳本都必須排隊等着,會拖延整個程序的執行。那麼如何讓程序像人類一樣可以多線程工作呢?
如果這條馬路只有一個車道,那麼五菱神車就可能會被法拉利擋住,如果是多車道(多線程)或者......,對吧?
- 回調函數
- 事件監聽
- 發佈訂閱模式
- Promise
- Generator(ES6)
- async(ES7)
JavaScript異步編程基本的解決方案:回調函數和事件監聽
示例:假設有兩個函數, f1 和 f2,f1 是一個需要一定時間的函數。
function f1() {
setTimeout(function () {
console.log('先執行 f1')
}, 2000)
}
function f2() {
console.log('再執行 f2')
}
回調函數
因爲 f1 是一個需要2s時間的函數,所以可以將 f2 寫成 f1 的 回調函數
,將同步操作變成異步操作,f1 不會阻塞程序的運行,f2 也無需空空等待,例如 JQuery 的 ajax。
function f1(f2){
setTimeout(function (){
console.log('先執行 f1')
}, 1000);
f2()
}
function f2(){
console.log('再執行 f2')
}
f1(f2);
回調執行結果:
總結:回調函數的優點是簡單、易於實現、便於理解,缺點是不利於代碼的閱讀和維護,多次回調會導致代碼高度耦合(Coupling),流程會很混亂,而且每個任務只能指定一個回調函數。
事件監聽
另一種思路是腳本的執行不取決代碼的順序,而取決於某個事件是否發生。採用事件驅動模式。
f1.on('done', f2);
//當f1發生done事件,就執行f2。然後,對f1進行改寫:
function f1(){
setTimeout(function () {
// f1的任務代碼
f1.trigger('done');
}, 1000);
}