在了解javascript運(yùn)行機(jī)制前 我們需要了解一下以下幾點(diǎn):
javascript是多線程還是單線程?
一個(gè)簡(jiǎn)單的測(cè)試
javascript中的 同步任務(wù)與異步任務(wù)
javascript中的 執(zhí)行棧
javascript中的回調(diào)函數(shù)和事件
Javascript中的任務(wù)隊(duì)列
javascript中的Event Loop
javascript是多線程還是單線程?
JavaScript語言的一大特點(diǎn)就是單線程,也就是說,同一個(gè)時(shí)間只能做一件事。
一個(gè)簡(jiǎn)單的測(cè)試,思考一下 以下代碼 的運(yùn)行結(jié)果
function syncAndAsync() {
console.log("1") //步驟1
setTimeout(() => {//步驟3
console.log("2")
}, 1000);
console.log("3")//步驟2
}
運(yùn)行結(jié)果:1,3,2
為什么 是這樣的結(jié)果呢?
如果把步驟2的時(shí)間改為0秒 結(jié)果會(huì)如何呢?
請(qǐng)讀完js的運(yùn)行機(jī)制后 ,答案就很明了了。
javascript中的同步任務(wù)與異步任務(wù)
因?yàn)閖avascript是單線程的 ,所以 javascript 把運(yùn)行的任務(wù),設(shè)計(jì)了兩種 同步任務(wù)和異步任務(wù)
同步任務(wù)指的是:在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù);
異步任務(wù)指的是:不進(jìn)入主線程、被主線程掛起的任務(wù),只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。當(dāng)主線程 的所有同步任務(wù)執(zhí)行完后,查看該任務(wù)隊(duì)列 的事件,對(duì)應(yīng)的任務(wù) 結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
javascript中的 執(zhí)行棧
所有同步任務(wù)都是在主線程上執(zhí)行的,這些同步任務(wù)在主線程上的執(zhí)行,這就是執(zhí)行棧。
javascript中的回調(diào)函數(shù)
回調(diào)函數(shù),就是那些會(huì)被主線程掛起來的任務(wù)。異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)主線程開始執(zhí)行異步任務(wù),就是執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。
Javascript中的任務(wù)隊(duì)列
"任務(wù)隊(duì)列"是一個(gè)事件的隊(duì)列(也可以理解成消息的隊(duì)列),隊(duì)列中對(duì)應(yīng)的任務(wù)有了結(jié)果(比如讀取文件(io操作),請(qǐng)求遠(yuǎn)程數(shù)據(jù)等等),就在"任務(wù)隊(duì)列"中添加一個(gè)事件,表示相關(guān)的異步任務(wù)可以進(jìn)入"執(zhí)行棧"了。主線程讀取"任務(wù)隊(duì)列",就是讀取里面有那些事件。
"任務(wù)隊(duì)列"中的事件,除了IO設(shè)備的事件以外,還包括一些用戶產(chǎn)生的事件(比如鼠標(biāo)點(diǎn)擊、頁面滾動(dòng)等等)。只要指定過回調(diào)函數(shù),這些事件發(fā)生時(shí)就會(huì)進(jìn)入"任務(wù)隊(duì)列",等待主線程讀取。
javascript中的Event Loop
主線程先執(zhí)行同步任務(wù),也就是執(zhí)行棧中的 任務(wù),當(dāng)執(zhí)行完所有的執(zhí)行棧中的任務(wù)后 ,從"任務(wù)隊(duì)列"中讀取事件,然后執(zhí)行對(duì)應(yīng)可執(zhí)行狀態(tài)的異步任務(wù)(回調(diào))。這個(gè)過程是不斷循環(huán)的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))。
異步執(zhí)行的運(yùn)行機(jī)制步驟如下:
1,所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack),排隊(duì)執(zhí)行。
2,主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。
3,一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列",看看里面有哪些事件。那些對(duì)應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
4,主線程不斷重復(fù)上面的第三步。