什么是同步和異步
先來(lái)看一段代碼
console.log(1)
setTimeout(function(){console.log(2)},0)
console.log(3)//1,3,2
代碼執(zhí)行的結(jié)果如上所示為1,3,2 很明顯與書(shū)寫的順序1,2,3不一致,所以我們可以簡(jiǎn)單的理解為代碼的執(zhí)行順序與書(shū)寫順序不同時(shí)就是異步.相對(duì)應(yīng)的,代碼順序與執(zhí)行順序相同的就是同步.
為什么有同步和異步
由于js同時(shí)只能執(zhí)行一個(gè)任務(wù)(即單線程,這個(gè)單線程是主線程),所以后面的任務(wù)只能在隊(duì)列中等待前一個(gè)的執(zhí)行.當(dāng)一個(gè)任務(wù)不能立刻得到結(jié)果時(shí)就會(huì)形成阻塞效應(yīng).這就是同步的缺陷.例如:taskC一定要等待taskB的結(jié)果.
function taskB(){
var response = $.ajax({
url:"/data.json",
async: false
})
return response
}
taskA()
taskB()
taskC()
為了解決該問(wèn)題,js會(huì)暫時(shí)將其放在任務(wù)隊(duì)列中等待,同時(shí)不斷檢查任務(wù)隊(duì)列中任務(wù)狀態(tài),一旦隊(duì)列中的任務(wù)得到結(jié)果(例如ajax從服務(wù)器得到結(jié)果)就重新將該任務(wù)放回主線程(一般采用回調(diào)函數(shù)的形式).
異步模式下,tackB請(qǐng)求ajax數(shù)據(jù)時(shí)taskC已經(jīng)開(kāi)始執(zhí)行,taskB暫時(shí)放在任務(wù)隊(duì)列等待結(jié)果,當(dāng)有結(jié)果時(shí)重新進(jìn)入主線程執(zhí)行.
function taskB(){
var result= $.ajax({
url:"/data.json",
async: true
})
return result
}
taskA()
taskB()
taskC()
常見(jiàn)的異步操作模式
- 回調(diào)函數(shù)
function f1(callback) {
callback();
}
function f2() {
console.log("f2被調(diào)用")
}
f1(f2);
- 事件監(jiān)聽(tīng)
f1.on('done', f2);
function f1() {
setTimeout(function () {
f1.trigger('done');
}, 1000);
}
function f2(){console.log("f2被調(diào)用")}
//f2會(huì)在f1執(zhí)行1s后被調(diào)用
- 發(fā)布/訂閱
事件可以理解成”信號(hào)“桶至,如果存在一個(gè)”信號(hào)中心“江场,某個(gè)任務(wù)執(zhí)行完成曼氛,就向信號(hào)中心”發(fā)布“(publish)一個(gè)信號(hào)靶擦,其他任務(wù)可以向信號(hào)中心”訂閱“(subscribe)這個(gè)信號(hào)块仆,從而知道什么時(shí)候自己可以開(kāi)始執(zhí)行
回調(diào)函數(shù)
維基百科的解釋是:
回調(diào)函數(shù)祭隔,或簡(jiǎn)稱回調(diào)(Callback 即call then back 被主函數(shù)調(diào)用運(yùn)算后會(huì)返回主函數(shù)),是指通過(guò)函數(shù)參數(shù)傳遞到其它代碼的锄俄,某一塊可執(zhí)行代碼的引用技竟。在js中允許簡(jiǎn)單的將函數(shù)名作為參數(shù)傳遞冰肴。
知乎上最高票的回答是用了一個(gè)比喻:
你到一個(gè)商店買東西,剛好你要的東西沒(méi)有貨灵奖,于是你在店員那里留下了你的電話嚼沿,過(guò)了幾天店里有貨了,店員就打了你的電話瓷患,然后你接到電話后就到店里去取了貨。在這個(gè)例子里遣妥,你的電話號(hào)碼就叫回調(diào)函數(shù)擅编,你把電話留給店員就叫登記回調(diào)函數(shù),店里后來(lái)有貨了叫做觸發(fā)了回調(diào)關(guān)聯(lián)的事件箫踩,店員給你打電話叫做調(diào)用回調(diào)函數(shù)爱态,你到店里去取貨叫做響應(yīng)回調(diào)事件。
https://www.zhihu.com/question/19801131/answer/13005983
所以傳給對(duì)方一個(gè)函數(shù),當(dāng)對(duì)方在合適的時(shí)機(jī)調(diào)用這個(gè)函數(shù),這個(gè)函數(shù)就是回調(diào)函數(shù).如下所示,當(dāng)f2作為f1的參數(shù)傳給f1,當(dāng)f1執(zhí)行到相應(yīng)位置時(shí)就會(huì)調(diào)用f2,這里f2就是回調(diào)函數(shù).
function f1(callback) {
console.log(1)
callback();
}
function f2() {
console.log(2)
}
f1(f2);
回調(diào)函數(shù)的優(yōu)點(diǎn)是便于理解,缺點(diǎn)是代碼間耦合程度高且程序流程不明晰,不方便理解維護(hù).