// 本文僅用于自己對(duì)知識(shí)理解和記錄
參考文章:http://www.ruanyifeng.com/blog/2014/10/event-loop.html
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
單線程的JavaScript
單線程一位置JavaScript一次只能做一件事奶甘;下一件事要排隊(duì);顯然我們認(rèn)為多線程更有效率艇潭;同時(shí)幾個(gè)窗口排隊(duì)辦事肯定快攒菠;
但是如果是多線程操作汁胆,a和b都修改c;a刪除了c一個(gè)屬性而b缺在a的該屬性上添加內(nèi)容;這是以誰(shuí)的操作為準(zhǔn)?
所以單線程反而把復(fù)雜的事簡(jiǎn)單化了
但是單線程上的任務(wù)排隊(duì)進(jìn)行古瓤,只有前一個(gè)任務(wù)完成才進(jìn)行下一個(gè)任務(wù),當(dāng)先一個(gè)任務(wù)耗時(shí)很長(zhǎng)時(shí)后面的任務(wù)就停滯了腺阳,例如ajax請(qǐng)求要等結(jié)果得到才會(huì)繼續(xù)執(zhí)行落君;
這時(shí)就衍生出了異步任務(wù)和同步任務(wù)
下面是引用阮一峰博客中的總結(jié)
(1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)亭引。
(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í)行棧枫夺,開(kāi)始執(zhí)行将宪。
(4)主線程不斷重復(fù)上面的第三步。
你不知道的javaScript(中卷)把下面要說(shuō)的micro task隊(duì)列叫做任務(wù)隊(duì)列橡庞,任務(wù)隊(duì)列也有循環(huán)叫做任務(wù)循環(huán)(job loop)甚至可能無(wú)限循環(huán)導(dǎo)致程序餓死较坛;事件循環(huán)(event loop)的隊(duì)列稱之為事件循環(huán)隊(duì)列;以事件隊(duì)列和任務(wù)隊(duì)列區(qū)分
事件循環(huán)(Event Loop)
事件隊(duì)列是一個(gè)先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)扒最,排在前面的事件丑勤,優(yōu)先被主線程讀取。主線程只要執(zhí)行棧一清空吧趣,事件隊(duì)列上第一位的事件就自動(dòng)進(jìn)入主線程法竞。
當(dāng)我們按下按鈕,他的事件處理程序會(huì)添加到事件隊(duì)列8强挫,并在主線程的執(zhí)行棧清空后立刻讀取事件隊(duì)列*中的第一個(gè)事件
這里就要說(shuō)到定時(shí)器(setTimeout)定時(shí)器并不是設(shè)置100ms就是在100ms后執(zhí)行代碼岔霸,而是在100ms后把要執(zhí)行的代碼添加到事件隊(duì)列。如果在這個(gè)時(shí)間點(diǎn)上主線程空閑則立即俯渤,所以setTimeout是不精確的呆细。
主線程從"事件隊(duì)列"中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的八匠,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))
任務(wù)(事件)和微任務(wù)(task 和 micro task)
然而在一次Ladaza的面試中被問(wèn)到setTimeout和Promise.then的執(zhí)行順序時(shí)我答砸了絮爷,這里捋一下。
看下面的log順序
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
答案應(yīng)該是:
// script start
// script end
// promise1
// promise2
// setTimeout
例子中setTimeout在事件隊(duì)列中加入一個(gè)新任務(wù)而console.log('script end');是當(dāng)前正在執(zhí)行任務(wù)(事件)的一部分所以在setTimeout之前打印梨树。
而其中promise.then屬于micro task坑夯,micro task排在當(dāng)前事件循環(huán)tick結(jié)尾處,只要當(dāng)前任務(wù)(事件)執(zhí)行完成清空所有的排隊(duì)的micro task抡四;
而setTimeout是調(diào)度另一個(gè)事件循環(huán)tick所以會(huì)在promise.then之后執(zhí)行
排隊(duì)的micro task也叫做job loop(任務(wù)循環(huán))
在瀏覽器環(huán)境中柜蜈,常見(jiàn)的 macro task 有 setTimeout、MessageChannel床嫌、postMessage跨释、setImmediate;常見(jiàn)的 micro task 有 MutationObsever 和 Promise.then厌处。
這里只解釋micro task的執(zhí)行時(shí)機(jī)鳖谈,后面結(jié)合vue的nextTick做理解。