摘要:設(shè)計(jì)為單線程設(shè)計(jì)為單線程還是跟他的用途有關(guān)試想一下如果設(shè)計(jì)為多線程那么同時(shí)修改和刪除同一個(gè)瀏覽器又該如何執(zhí)行需要異步我在執(zhí)行但用戶不知道你好啊上圖例子循環(huán)耗時(shí)會(huì)很久這意味著用戶得不到你好啊的響應(yīng)就會(huì)下意識(shí)會(huì)認(rèn)為瀏覽器卡死了所以必須要有異步通
js設(shè)計(jì)為單線程
js設(shè)計(jì)為單線程還是跟他的用途有關(guān)js需要異步
試想一下 如果js設(shè)計(jì)為多線程 那么同時(shí)修改和刪除同一個(gè)dom 瀏覽器又該如何執(zhí)行?
for (var i=0;i<9999;i++){ console.log("我在執(zhí)行 但用戶不知道") } console.log("你好啊")
上圖例子 for循環(huán)耗時(shí)會(huì)很久一方面代碼慢慢跑著 另一方面用戶已經(jīng)抓狂 js事件循環(huán) (說白了不斷執(zhí)行倆步驟) 一、歸類
這意味著 用戶得不到 "你好啊" 的響應(yīng) 就會(huì)下意識(shí)會(huì)認(rèn)為瀏覽器卡死了 所以js必須要有異步
js通過事件循環(huán)來實(shí)現(xiàn)異步 這也是js的運(yùn)行機(jī)制
遇到同步任務(wù)直接執(zhí)行,遇到異步任務(wù)分類為宏任務(wù)(macro-task)和微任務(wù)(micro-task)。
宏任務(wù):整體的Script setTimeout setInterval
微任務(wù):Promise process.nextTick
請(qǐng)看示例代碼:
// 這是一個(gè)同步任務(wù) console.log("1") --------> 直接被執(zhí)行 目前打印結(jié)果為:1 // 這是一個(gè)宏任務(wù) setTimeout(function () { --------> 整體的setTimeout被放進(jìn)宏任務(wù)列表 console.log("2") 目前宏任務(wù)列表記為【s2】 }); new Promise(function (resolve) { // 這里是同步任務(wù) console.log("3"); --------> 直接被執(zhí)行 resolve(); 目前打印結(jié)果為:1、3 // then是一個(gè)微任務(wù) }).then(function () { --------> 整體的then[包含里面的setTimeout]被放進(jìn)微任務(wù)列表 console.log("4") 目前微任務(wù)列表記為【t45】 setTimeout(function () { console.log("5") }); });
第一輪小結(jié): 執(zhí)行到這里的結(jié)果:1、3 宏任務(wù)列表如下: setTimeout(function () { console.log("2") }); 微任務(wù)列表如下: then(function () { console.log("4") setTimeout(function () { console.log("5") }); });二、有微則微,無微則宏
如果微任務(wù)列表里面有任務(wù) 會(huì)執(zhí)行完畢后在執(zhí)行宏任務(wù) (ps:開篇有流程圖)
瀏覽器瞅了一眼微任務(wù)列表 發(fā)現(xiàn)里面有微任務(wù) 就開始全部執(zhí)行 then(function () { console.log("4") --------> 直接被執(zhí)行 目前打印結(jié)果為:1、3、4 setTimeout(function () { --------> 被放進(jìn)宏任務(wù)列表了 console.log("5") 目前宏任務(wù)列表記為【s2、s5】 }); }); 瀏覽器發(fā)現(xiàn)微任務(wù)執(zhí)行完畢了 開始執(zhí)行宏任務(wù)列表 setTimeout(function () { console.log("2") --------> 直接被執(zhí)行 目前打印結(jié)果為:1、3、4、2 }); setTimeout(function () { console.log("5") --------> 直接被執(zhí)行 目前打印順序?yàn)椋?1、3、4、2、5、5 }); 最終結(jié)果為: 1、3、4、2、5三、總結(jié) + 實(shí)戰(zhàn)
反復(fù)執(zhí)行以上步驟 就是事件循環(huán)(event loop)
一定要分的清任務(wù)類型 (宏任務(wù) 和 微任務(wù))
TIP: 為了容易辨別起名為p1(p開頭 里面打印1) process.nextTick(function() { --------> 被放微任務(wù)列表 console.log("1"); 微任務(wù)列表記為:【p1】 }) new Promise(function (resolve) { console.log("2"); --------> 直接執(zhí)行 resolve(); 目前打印順序?yàn)椋? }).then(function () { --------> 整體的then被放進(jìn)微任務(wù)列表[包含其中的setTimeout 4] console.log("3"); 微任務(wù)列表記為:【p1 t34】 setTimeout(function () { console.log("4") }); }); setTimeout(function () { --------> 被放宏任務(wù)列表 console.log("5") 宏任務(wù)列表記為:【s5】 }); new Promise(function (resolve) { setTimeout(function () { --------> 被放宏任務(wù)列表 console.log("6") 宏任務(wù)列表記為:【s5 s6】 }); resolve() }).then(function () { --------> 整體的then被放進(jìn)微任務(wù)列表[包含其中的setTimeout和其中的多層嵌套] setTimeout(function () { 微任務(wù)列表記為:【p1 t34 t789】 console.log("7") new Promise(function (resolve) { setTimeout(function () { console.log("8") }); resolve() }).then(function () { setTimeout(function () { console.log("9") }); }); }); }); console.log("10") --------> 直接執(zhí)行 目前打印順序?yàn)椋?、10
第一輪小結(jié): 執(zhí)行結(jié)果為:2、10 宏任務(wù)列表如下: // s5 setTimeout(function () { console.log("5") }); //s6 setTimeout(function () { console.log("6") }); 微任務(wù)列表如下: // p1 process.nextTick(function() { console.log("1"); }) // t34 then(function () { console.log("3"); setTimeout(function () { console.log("4") }); }); // t789 then(function () { setTimeout(function () { console.log("7") new Promise(function (resolve) { setTimeout(function () { console.log("8") }); resolve() }).then(function () { setTimeout(function () { console.log("9") }); }); });
開始執(zhí)行第二輪: 有微任務(wù) 先執(zhí)行微任務(wù) 將微任務(wù)列表代碼塊搬下來 // p1 process.nextTick(function() { --------> 執(zhí)行p1 console.log("1"); 目前打印順序?yàn)椋?、10、1 }) // t34 then(function () { console.log("3"); --------> 直接執(zhí)行 目前打印順序?yàn)椋?、10、1、3 setTimeout(function () { --------> 被放宏任務(wù)列表 console.log("4") 宏任務(wù)列表記為:【s5 s6 s4】 }); }); // t789 then(function () { setTimeout(function () { --------> 被放宏任務(wù)列表 console.log("7") 宏任務(wù)列表記為:【s5 s6 s4 s789】 new Promise(function (resolve) { setTimeout(function () { console.log("8") }); resolve() }).then(function () { setTimeout(function () { console.log("9") }); }); }); }) 微任務(wù)執(zhí)行完畢了 該執(zhí)行我們的宏任務(wù)列表了 因?yàn)槲⑷蝿?wù)里面包含一部分宏任務(wù) 所以現(xiàn)在的宏任務(wù)列表已經(jīng)增加了 現(xiàn)在把當(dāng)前的宏任務(wù)列表搬下來 //s5 setTimeout(function () { --------> 執(zhí)行s5 console.log("5") 目前打印順序?yàn)椋?、10、1、3、5 }); //s6 setTimeout(function () { --------> 執(zhí)行s6 console.log("6") 目前打印順序?yàn)椋?、10、1、3、5、6 }); //s4 setTimeout(function () { --------> 執(zhí)行s4 console.log("4") 目前打印順序?yàn)椋?、10、1、3、5、6、4 }); // s789 setTimeout(function () { --------> 執(zhí)行s789 console.log("7") 目前打印順序?yàn)椋?、10、1、3、5、6、4、7 new Promise(function (resolve) { setTimeout(function () { --------> 被放宏任務(wù)列表 console.log("8") 宏任務(wù)列表記為:【s8】 }); resolve() }).then(function () { --------> 整體的then被放微任務(wù)列表[包含里面的setTimeout] setTimeout(function () { 微任務(wù)列表記為:【t9】 console.log("9") }); }); });
再次小結(jié): 當(dāng)前結(jié)果:2、10、1、3、5、6、4、7 馬上就要執(zhí)行完了心里萬分激動(dòng)啊 ( 瀏覽器的內(nèi)心獨(dú)白 ^▽^ ...) 宏任務(wù)列表如下: // s8 setTimeout(function () { console.log("8") }); 微任務(wù)列表如下: // t9 then(function () { setTimeout(function () { console.log("9") }); }); 繼續(xù)執(zhí)行 依舊遵循有微則微 無微則宏 瀏覽器發(fā)現(xiàn)有一條微任務(wù) 那就開始執(zhí)行吧~ //t9 then(function () { setTimeout(function () { --------> 執(zhí)行t9 把里面的setTimeout放入宏任務(wù)列表 console.log("9") 宏任務(wù)列表記為:【s8 s9】 }); }); 微任務(wù)列表執(zhí)行完畢 開始執(zhí)行宏任務(wù)(宏任務(wù)剛剛又有新增哦~[s9]) // s8 setTimeout(function () { --------> 執(zhí)行s8 console.log("8") 目前打印順序?yàn)椋?、10、1、3、5、6、4、7、8 }); // s9 setTimeout(function () { --------> 執(zhí)行s9 console.log("9") 目前打印順序?yàn)椋?、10、1、3、5、6、4、7、8、9 }); 到這里 微任務(wù)列表 和 宏任務(wù)列表均為空 就執(zhí)行完畢了
再此留下一道沒有答案的題供練手
new Promise(function (resolve) { console.log("1"); resolve(); }).then(function () { setTimeout(function () { console.log("2") }); }); setTimeout(function () { console.log("3") process.nextTick(function() { console.log("4"); }) process.nextTick(function() { console.log("5"); }) }); new Promise(function (resolve) { console.log("6"); resolve(); setTimeout(function () { console.log("7") new Promise(function (resolve) { console.log("8"); resolve(); }).then(function () { setTimeout(function () { console.log("9") }); }); }); }).then(function () { setTimeout(function () { console.log("10") }); new Promise(function (resolve) { console.log("11"); resolve(); }).then(function () { setTimeout(function () { console.log("12") }); }); });
本人學(xué)識(shí)有限 文章多有不足
若有錯(cuò)誤 請(qǐng)大方指出 以免誤導(dǎo)他人
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104037.html
摘要:規(guī)范中定義了瀏覽器何時(shí)進(jìn)行渲染更新,了解它有助于性能優(yōu)化。結(jié)合一些資料,對(duì)上邊規(guī)范給出一些理解有誤請(qǐng)指正每個(gè)線程都有自己的。列為,列為,列為。我們都知道是單線程,渲染計(jì)算和腳本運(yùn)行共用同一線程網(wǎng)絡(luò)請(qǐng)求會(huì)有其他線程,導(dǎo)致腳本運(yùn)行會(huì)阻塞渲染。 本文轉(zhuǎn)自blog 轉(zhuǎn)載請(qǐng)注明出處 異步的思考 event loops隱藏得比較深,很多人對(duì)它很陌生。但提起異步,相信每個(gè)人都知道。異步背后的靠山就是...
摘要:我不該動(dòng)你的,寫在前面的話本意是想好好研究下,看了幾篇博客后,才意識(shí)到作為前端打字員的我有多無知,這坑忒深了。這樣的話,如果是第一種解釋,應(yīng)該在運(yùn)行之前,頁面就變成了紅色否則就應(yīng)該采取第二種解釋。 我不該動(dòng)你的,Event Loops 寫在前面的話 本意是想好好研究下 Event Loops, 看了幾篇博客后,才意識(shí)到作為前端打字員的我有多無知,這坑忒深了。 macrotask?,mi...
摘要:但是導(dǎo)致了很明顯的性能問題。上述兩個(gè)例子其實(shí)是在這個(gè)中找到的,第一個(gè)使用的版本是,這個(gè)版本的實(shí)現(xiàn)是采用了,而后因?yàn)榈睦锏挠?,于是尤雨溪更改了?shí)現(xiàn),換成了,也就是后一個(gè)所使用的。后來尤雨溪了解到是將回調(diào)放入的隊(duì)列。 結(jié)論 對(duì)于event loop 可以抽象成一段簡(jiǎn)單的代碼表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...
摘要:但是導(dǎo)致了很明顯的性能問題。上述兩個(gè)例子其實(shí)是在這個(gè)中找到的,第一個(gè)使用的版本是,這個(gè)版本的實(shí)現(xiàn)是采用了,而后因?yàn)榈睦锏挠?,于是尤雨溪更改了?shí)現(xiàn),換成了,也就是后一個(gè)所使用的。后來尤雨溪了解到是將回調(diào)放入的隊(duì)列。 結(jié)論 對(duì)于event loop 可以抽象成一段簡(jiǎn)單的代碼表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...
閱讀 2078·2021-10-11 10:59
閱讀 935·2021-09-23 11:21
閱讀 3566·2021-09-06 15:02
閱讀 1620·2021-08-19 10:25
閱讀 3378·2021-07-30 11:59
閱讀 2375·2019-08-30 11:27
閱讀 2586·2019-08-30 11:20
閱讀 2978·2019-08-29 13:15