因?yàn)镴avaScript是單線(xiàn)程執(zhí)行的荒典,意味著同一個(gè)時(shí)間點(diǎn)酪劫,只有一個(gè)任務(wù)在運(yùn)行。單線(xiàn)程就意味著寺董,所有任務(wù)需要排隊(duì)覆糟,前一個(gè)任務(wù)結(jié)束,才會(huì)執(zhí)行后一個(gè)任務(wù)遮咖。如果前一個(gè)任務(wù)耗時(shí)很長(zhǎng)滩字,后一個(gè)任務(wù)就不得不一直等著。只要有一個(gè)任務(wù)耗時(shí)很長(zhǎng)御吞,后面的任務(wù)都必須排隊(duì)等著麦箍,會(huì)拖延整個(gè)程序的執(zhí)行。常見(jiàn)的瀏覽器無(wú)響應(yīng)(假死)陶珠,往往就是因?yàn)槟骋欢蜫avascript代碼長(zhǎng)時(shí)間運(yùn)行(比如死循環(huán))挟裂,導(dǎo)致整個(gè)頁(yè)面卡在這個(gè)地方,其他任務(wù)無(wú)法執(zhí)行背率。
為了解決這個(gè)問(wèn)題,Javascript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)嫩与。
同步:一定要等任務(wù)執(zhí)行完了寝姿,得到結(jié)果,才執(zhí)行下一個(gè)任務(wù)划滋。
異步:不等任務(wù)執(zhí)行完饵筑,直接執(zhí)行下一個(gè)任務(wù)。
比如
fn1()
fn2()
fn1執(zhí)行完才執(zhí)行fn2处坪。
異步:不等任務(wù)執(zhí)行完根资,直接執(zhí)行下一個(gè)任務(wù)架专。
如如
function f1(){
setTimeout(function () {
console.log(1)
}, 1000);
}
function f2(){
console.log(2)
}
f1()
f2()
這段代碼就是就是異步,f2沒(méi)有等f(wàn)1執(zhí)行完畢就執(zhí)行了玄帕。
常見(jiàn)的異步有:
setTimeout部脚、Ajax請(qǐng)求、dom事件裤纹,他們都屬于在瀏覽器的webApi中委刘。異步是通過(guò)瀏覽器實(shí)現(xiàn)的,瀏覽器為這些耗時(shí)任務(wù)開(kāi)辟了另外的線(xiàn)程鹰椒。
圖片來(lái)自Philip Roberts的演講《Help, I'm stuck in an event-loop》
回調(diào)(callback)
瀏覽器把異步的任務(wù)放在callback queue中漆际,要想拿到必須使用回調(diào)(callback)淆珊,當(dāng)JS里的棧stack清空時(shí),說(shuō)明一個(gè)任務(wù)已經(jīng)執(zhí)行完了奸汇,這時(shí)就會(huì)從callback queue中尋找下一個(gè)人任務(wù)推入棧中(這個(gè)尋找的過(guò)程施符,叫做event loop,因?yàn)樗偸茄h(huán)的查找任務(wù)隊(duì)列里是否還有任務(wù))茫蛹。
所以簡(jiǎn)單說(shuō)操刀,通過(guò)webApi創(chuàng)建異步任務(wù)。任務(wù)完成時(shí)婴洼,如果有指定了回調(diào)函數(shù)骨坑,將回調(diào)函數(shù)放入task queue中;如果沒(méi)有指定回調(diào)函數(shù)柬采,這個(gè)事件就被丟棄欢唾。回調(diào)函數(shù):定義了異步任務(wù)完成時(shí)所要執(zhí)行的操作粉捻,包括事件和定時(shí)器所指定的異步任務(wù)礁遣。
比如
function f1(callback){
setTimeout(function () {
console.log(1)
callback();
}, 1000);
}
function f2(){
console.log(2)
}
f1(f2)
在1秒后f1執(zhí)行結(jié)束,才會(huì)調(diào)用f2執(zhí)行肩刃。