淺談,JavaScript 運行機制和Event Loop
JavaScript是一個非常靈活的語言且是單線程所謂是單線程就好比你去一個銀行蛾娶,銀行只開設(shè)了一個窗口,然而一個窗口就好比一個線程,取錢的人就好比JS代碼楚午。也就是說
javascript是按照語句出現(xiàn)的順序執(zhí)行的
其實這樣說是很嚴(yán)謹(jǐn)宴偿,例如:
setTimeout(
function(){
console.log('定時器開始啦')
});
new Promise(
function(resolve){
console.log('馬上執(zhí)行for循環(huán)啦');
for(var i = 0; i < 100; i++)
{
i == 99 && resolve(); }
}).then(
function(){
console.log('執(zhí)行then函數(shù)啦')
});
console.log('代碼執(zhí)行結(jié)束');
你覺得會是一行一行的執(zhí)行嗎湘捎?為什么會出現(xiàn)我們不一樣的結(jié)果呢,一行一行的執(zhí)行對我們執(zhí)行效果很不好那么怎么解決呢窄刘?這就涉及到JS 中的
同步任務(wù)
異步任務(wù)
何為同步呢窥妇?簡單的理解就是你向一個女孩子表白,你打電話給她娩践,說喜歡她活翩。這個過程你一直不掛電話,啥事也不干就等她回答翻伺,對于你來說就是同步材泄。比如頁面骨架和頁面元素的渲染就是同步,而異步呢穆趴,我進常用AJAX請求脸爱。下面一張圖讓我們來體會一下:
那么這張圖說明了什么呢?我們看看
同步和異步任務(wù)分別進入不同的執(zhí)行"場所"未妹,同步的進入主線程簿废,異步的進入Event Table并注冊函數(shù)。
當(dāng)指定的事情完成時络它,Event Table會將這個函數(shù)移入Event Queue族檬。
主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會去Event Queue讀取對應(yīng)的函數(shù)化戳,進入主線程執(zhí)行单料。
上述過程會不斷重復(fù)埋凯,也就是常說的Event Loop(事件循環(huán))。
我們不禁要問了扫尖,那怎么知道主線程執(zhí)行棧為空鞍锥浴?js引擎存在monitoring process進程换怖,會持續(xù)不斷的檢查主線程執(zhí)行棧是否為空甩恼,一旦為空,就會去Event Queue那里檢查是否有等待被調(diào)用的函數(shù)沉颂。
那我們來看一下代碼吧条摸,加深理解。
var data={}
$.ajax(
{
url:xxxxxx,
data:data,
success:() => {
console.log('發(fā)送成功!');
}
})
console.log('代碼執(zhí)行結(jié)束');
有人這么平淡無奇的AJAX有啥奇怪铸屉,不妨我來看看這段代碼的含義钉蒲,
ajax進入Event Table,注冊回調(diào)函數(shù)success彻坛。
執(zhí)行console.log('代碼執(zhí)行結(jié)束')顷啼。
ajax事件完成,回調(diào)函數(shù)success進入Event Queue小压。
主線程從Event Queue讀取回調(diào)函數(shù)success并執(zhí)行线梗。
有的同學(xué)就覺得我明白了,下面我再來一段代碼看看怠益,
console.log('main1');
process.nextTick(function() {
console.log('process.nextTick1');
});
setTimeout(function() {
console.log('setTimeout');
process.nextTick(function() {
console.log('process.nextTick2');
});
}, 0);
new Promise(function(resolve, reject) {
console.log('promise');
resolve();
}).then(function() {
console.log('promise then');
});
console.log('main2');
不妨我們來分析下:
開始執(zhí)行全局SCRIPT宏任務(wù)仪搔,輸出 main1,process.nextTick 放入tickTaskQueen蜻牢,setTimeout放入 macroTaskQueen, new Promise 執(zhí)行 輸出 promise烤咧,then 方法 放入 MicroTaskQueen , 接著 最后一行代碼 console.log 輸出 main2
當(dāng)前的 宏任務(wù)執(zhí)行完畢,開始清空微任務(wù)抢呆,先清空tickTaskQueen ,執(zhí)行 console.log('process.nextTick1'); 輸出'process.nextTick1煮嫌;再清空MicroTaskQueen執(zhí)行 console.log('promise then'); 輸出promise then;微任務(wù)全部清空抱虐。
開始下次 eventLoop; 執(zhí)行 setTimeout昌阿; 第一行 console.log('setTimeout'); 輸出setTimeout; process.nextTick 將任務(wù)放入了tickTaskQueen恳邀;當(dāng)前宏任務(wù)執(zhí)行完畢懦冰;開始清空MicroTaskQueen,清空tickTaskQueen ,執(zhí)行 console.log('process.nextTick2');輸出process.nextTick2谣沸;
順便附上圖:
這幅圖很好說明時間循環(huán)的機制吧刷钢,好了這次就到這里,歡迎大家提意見乳附。