JavaScript是單線程的,具有同步執(zhí)行模型。單線程意味著一次執(zhí)行一個(gè)命令。同步意味著一次執(zhí)行一行代碼,即為了代碼的出現(xiàn)而在時(shí)間上執(zhí)行一行代碼。因此,在JavaScript中,一次只發(fā)生一件事。
執(zhí)行上下文
JavaScript引擎與瀏覽器中的其他引擎交互。在JavaScript執(zhí)行堆棧中,底部有全局上下文,然后當(dāng)我們調(diào)用函數(shù)時(shí),JavaScript引擎會(huì)為各自的函數(shù)創(chuàng)建新的執(zhí)行上下文。當(dāng)被調(diào)用的函數(shù)退出時(shí),它的執(zhí)行上下文將從堆棧中彈出,然后下一個(gè)執(zhí)行上下文被彈出,以此類(lèi)推。
例如
function abc(){
console.log('abc');}function xyz(){
abc()
console.log('xyz');}var one = 1;xyz();
在上面的代碼中,將創(chuàng)建一個(gè)全局執(zhí)行上下文,并且在此上下文中var one
它的價(jià)值是1.當(dāng)調(diào)用xyz()調(diào)用時(shí),將創(chuàng)建一個(gè)新的執(zhí)行上下文,如果我們?cè)趚yz函數(shù)中定義了任何變量,這些變量將存儲(chǔ)在xyz()的執(zhí)行上下文中。在xyz函數(shù)中,我們調(diào)用abc(),然后創(chuàng)建abc()執(zhí)行上下文并放到執(zhí)行堆棧上.現(xiàn)在,當(dāng)abc()完成其上下文從堆棧中彈出,那么xyz()上下文從堆棧中彈出,然后全局上下文將被彈出.
現(xiàn)在是關(guān)于異步回調(diào);異步意味著一次不止一個(gè)。
就像執(zhí)行堆棧一樣,事件隊(duì)列..當(dāng)我們希望得到JavaScript引擎中某些事件的通知時(shí),我們可以監(jiān)聽(tīng)該事件,并將該事件放在隊(duì)列中。例如,Ajax請(qǐng)求事件或HTTP請(qǐng)求事件。
每當(dāng)執(zhí)行堆棧為空時(shí)(如上面的代碼示例所示),JavaScript引擎會(huì)定期查看事件隊(duì)列,并查看是否有任何事件需要通知。例如,隊(duì)列中有兩個(gè)事件,一個(gè)Ajax請(qǐng)求和一個(gè)HTTP請(qǐng)求。它還想看看是否有一個(gè)函數(shù)需要在該事件觸發(fā)器上運(yùn)行.因此,JavaScript引擎會(huì)收到關(guān)于事件的通知,并知道要在該事件上執(zhí)行的相應(yīng)函數(shù).因此JavaScript引擎調(diào)用處理程序函數(shù),在示例中,例如AjaxHandler()將被調(diào)用,就像調(diào)用函數(shù)時(shí)一樣,它的執(zhí)行上下文被放置在執(zhí)行上下文中,現(xiàn)在函數(shù)執(zhí)行完成,事件Ajax請(qǐng)求也從事件隊(duì)列中刪除.當(dāng)AjaxHandler()完成時(shí),執(zhí)行堆棧是空的,因此引擎再次查看事件隊(duì)列,并運(yùn)行HTTP請(qǐng)求的事件處理程序函數(shù),這是隊(duì)列中的下一個(gè)。重要的是要記住,只有在執(zhí)行堆棧為空時(shí)才會(huì)處理事件隊(duì)列。
例如,參見(jiàn)下面解釋Javascript引擎執(zhí)行堆棧和事件隊(duì)列處理的代碼。
function waitfunction() {
var a = 5000 + new Date().getTime();
while (new Date() < a){}
console.log('waitfunction() context will be popped after this line');}function clickHandler() {
console.log('click event handler...'); }document.addEventListener('click', clickHandler);waitfunction(); //a new context for this function is created and placed on the execution stackconsole.log('global context will be popped after this line');
和
<html>
<head>
</head>
<body>
<script src="program.js"></script>
</body></html>
現(xiàn)在運(yùn)行網(wǎng)頁(yè)并單擊頁(yè)面,然后查看控制臺(tái)上的輸出。輸出將是
waitfunction() context will be popped after this lineglobal context will be emptied after this line
click event handler...
JavaScript引擎正在同步運(yùn)行代碼,正如在執(zhí)行上下文部分中所解釋的那樣,瀏覽器正在異步地將內(nèi)容放入事件隊(duì)列中。因此,需要很長(zhǎng)時(shí)間才能完成的函數(shù)可以中斷事件處理。JavaScript以這種方式處理瀏覽器中發(fā)生的事件,如果需要運(yùn)行偵聽(tīng)器,則當(dāng)執(zhí)行堆棧為空時(shí),引擎將運(yùn)行它。事件是按照它們發(fā)生的順序來(lái)處理的,所以異步部分是關(guān)于引擎外部正在發(fā)生的事情,即當(dāng)這些外部事件發(fā)生時(shí),引擎應(yīng)該做什么。
所以JavaScript總是同步的。