JS之EventLoop

EventLoop

作為一個前端er阀坏,必須知道的技能之一~由于我之前時候做Android開發(fā)的,特此記錄下笆檀。

js是單線程的忌堂,那如何協(xié)調(diào)事件(event),用戶交互(user interaction)酗洒,腳本(script)士修,渲染(rendering),網(wǎng)絡(luò)(networking)等樱衷,用戶代理(user agent)等等呢~此時就需要用到EventLoop——事件循環(huán)棋嘲。

JS有個任務隊列的概念:

macrotask(宏任務):script(整體代碼), XHR回調(diào)、事件回調(diào)(鼠標鍵盤事件)setTimeout, setInterval, setImmediate(node獨有), I/O, UI rendering

microtask(微任務):process.nextTick(node獨有), Promises.then, Object.observe(廢棄), MutationObserver

new Promise 屬于主線程(外層宏) 但是Promises.then 是微任務>毓稹沸移!

詳細步驟:
1.選擇當前要執(zhí)行的宏任務隊列,選擇一個最先進入任務隊列的宏任務,如果沒有宏任務可以選擇雹锣,則會跳轉(zhuǎn)至microtask的執(zhí)行步驟网沾。
2.將事件循環(huán)的當前運行宏任務設(shè)置為已選擇的宏任務。
3.運行宏任務蕊爵。
4.將事件循環(huán)的當前運行任務設(shè)置為null辉哥。
5.將運行完的宏任務從宏任務隊列中移除。
6.microtasks步驟:進入microtask檢查點攒射。
7.更新界面渲染醋旦。
8.返回第一步。

只要主線程空了会放,就會讀取任務列隊饲齐,這就是 js 的運行機制,也被稱為 event loop(事件循環(huán))鸦概。
需要注意的一點是:在同一個上下文中箩张,總的執(zhí)行順序為同步代碼—>microTask—>macroTask

下面看代碼:

console.log("start")
setTimeout(()=>{
    console.log('timer1')
    new Promise(function(resolve){
     console.log(" promise start ")
      resolve();
}).then(function() {
        console.log('promise1')
    })
}, 0)

setTimeout(()=>{
    console.log('timer2')
    Promise.resolve().then(function() {
        console.log('promise2')
    })
}, 0)
console.log("end")

瀏覽器輸出:
start
end
time1
promise start
promise1
time2
promise2

首先先執(zhí)行同步任務,先打印start,
執(zhí)行到第一個setTimeout屬于宏任務 所以掛起放到宏任務窗市,遇到第二個setTimeout也是掛起放到宏任務,
接著打印end先慷,同步任務執(zhí)行完成->JS執(zhí)行棧為空->去查找微任務:微任務為空,接著查找宏任務咨察,
執(zhí)行第一個宏任務setTimeout 打印timer1论熙,接著執(zhí)行newPromise,輸出 promise start 摄狱,再接著Promise.then屬于微任務脓诡,掛起放到微任務中。
宏任務執(zhí)行完成->JS執(zhí)行棧為空>去查找微任務:微任務里有任務媒役,一次執(zhí)行完祝谚,輸出promise1。
后面接著循環(huán)去查找宏任務~酣衷。
換一種方式:

console.log("start")
setTimeout(()=>{
    console.log('timer1')
    
}, 0)

new Promise(function(resolve){
     console.log(" promise start ")  //主線程(外層宏)
      resolve();
}).then(function() {
        console.log('promise1')交惯;//這里是微任務
    })

setTimeout(()=>{
    console.log('timer2')
    Promise.resolve().then(function() {
        console.log('promise2')
    })
}, 0)
console.log("end")

瀏覽器輸出:
start
promise start
end
promise1
timer1
time2
promise2

console.log('1');
setTimeout(function() {
    console.log('3');
    new Promise(function(resolve) {
        console.log('3.1');
        resolve();
    }).then(function() {
        console.log('4')
    })
})

new Promise(function(resolve) {
    console.log('1.1');
    resolve();
}).then(function() {
    console.log('2')
})

setTimeout(function() {
    console.log('5');
    new Promise(function(resolve) {
        console.log('5.1');
        resolve();
    }).then(function() {
        console.log('6')
    })
})

瀏覽器輸出:
1
1.1
2
3
3.1
4
5
5.1
6

async/await

如果遇到async的代碼 await后面的程序就掛起 類似于微任務 等到后面的同步任務執(zhí)行完了再執(zhí)行
執(zhí)行順序按照微任務執(zhí)行順序來執(zhí)行

console.log("start")
async function f1(){
      console.log("f1 start")
      var aa= await 1;//到這里掛起,后面先不執(zhí)行
     console.log("f1 end")
}
setTimeout(function(){
    console.log("setTimeout ")
},0)
f1();
var pr1 =new Promise(function(resolve){
     console.log(" promise start ")
      resolve();
}).then(function(resoult){
    console.log("promise then")
})
console.log("end")

結(jié)果: start=>f1 start=> promise start=> end=>f1 end=> promise then =>setTimeout

變形一下 async和promise交換位置

console.log("start")
async function f1(){
      console.log("f1 start")
      var aa= await 1;
     console.log("f1 end")
}
setTimeout(function(){
    console.log("setTimeout ")
},0)

var pr1 =new Promise(function(resolve){
     console.log(" promise start ")
      resolve();
}).then(function(resoult){
    console.log("promise then")
})
f1();
console.log("end")

結(jié)果: start=>promise start=>f1 start=> end=>=> promise then =>f1 end=>setTimeout

再變形:

console.log("start")
async function f1(){
      console.log("f1 start")
      var aa= await 1;
setTimeout(function(){
    console.log("setTimeout 2")
},0)
}
setTimeout(function(){
    console.log("setTimeout ")
},0)
var pr1 =new Promise(function(resolve){
     console.log(" promise start ")
      resolve();
}).then(function(resoult){
    console.log("promise then")
})
f1();
console.log("end")

結(jié)果: start=>promise start=> f1 start=> end=> promise then =>setTimeout=>setTimeout 2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末穿仪,一起剝皮案震驚了整個濱河市席爽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啊片,老刑警劉巖只锻,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異紫谷,居然都是意外死亡齐饮,警方通過查閱死者的電腦和手機捐寥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沈矿,“玉大人上真,你說我怎么就攤上這事「牛” “怎么了睡互?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長陵像。 經(jīng)常有香客問我就珠,道長,這世上最難降的妖魔是什么醒颖? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任妻怎,我火速辦了婚禮,結(jié)果婚禮上泞歉,老公的妹妹穿的比我還像新娘逼侦。我一直安慰自己,他們只是感情好腰耙,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布榛丢。 她就那樣靜靜地躺著,像睡著了一般挺庞。 火紅的嫁衣襯著肌膚如雪晰赞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天选侨,我揣著相機與錄音掖鱼,去河邊找鬼。 笑死援制,一個胖子當著我的面吹牛戏挡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晨仑,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼增拥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了寻歧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤秩仆,失蹤者是張志新(化名)和其女友劉穎码泛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澄耍,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡噪珊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年晌缘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痢站。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡磷箕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阵难,到底是詐尸還是另有隱情岳枷,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布呜叫,位于F島的核電站空繁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏朱庆。R本人自食惡果不足惜盛泡,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娱颊。 院中可真熱鬧傲诵,春花似錦、人聲如沸箱硕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颅痊。三九已至殖熟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間斑响,已是汗流浹背菱属。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留舰罚,地道東北人纽门。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像营罢,于是被迫代替她去往敵國和親赏陵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355