新聞中心
簡短的概括:
- JS中的單線程異步編程
- EventLoop 事件循環(huán)機(jī)制
- 宏任務(wù) macrotask [?m?kro?]
- 微任務(wù) microtask [?ma?kro?]
- JS中的同步異步編程
1?JS是單線程的,怎么達(dá)到異步編程:
1)JS是單線程的,大部分代碼都是同步編程。

公司主營業(yè)務(wù):網(wǎng)站制作、成都網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出從化免費(fèi)做網(wǎng)站回饋大家。
2)JS中利用瀏覽器的多線程機(jī)制,基于單線程的EventLoop(事件循環(huán)機(jī)制)實現(xiàn)出異步的效果。
2?event loop (微任務(wù)與宏任務(wù)):
1)微任務(wù) (microtask):優(yōu)先級高,并且可以插隊,不是先定義先執(zhí)行。包括:promise.then,async/await [generator],requestAnimationFrame,observer,MutationObserver,setImmediate。
2)宏任務(wù) (macrotask):優(yōu)先級低,先定義的先執(zhí)行。包括:ajax,setTimeout,setInterval,事件綁定,postMessage,MessageChannel(用于消息通訊)。
3?根據(jù)事件循環(huán)機(jī)制,重新梳理一下流程:
+先找微任務(wù)隊列,如果微任務(wù)隊列中有,先從微任務(wù)隊列中,一般按照存放順序獲取并且去執(zhí)行。
+如果微任務(wù)隊列中沒有,則再去宏任務(wù)隊列中查找,在宏任務(wù)隊列中,一般是按照誰先到達(dá)執(zhí)行的條件,就先把誰拿出來執(zhí)行。
??济嬖囶}:EventLoop事件循環(huán)
面試題1:
- console.log('1') // 1
- async function async1() {
- console.log('2') // 2
- await setTimeout(() => {
- console.log('3') // 8
- }, 0)
- console.log('4') // 5
- }
- setTimeout(() => {
- console.log('5') // 7
- }, 0)
- async1()
- new Promise(function (resolve) {
- console.log('6') // 3
- resolve()
- }).then(function () {
- console.log('7') // 6
- })
- console.log('8') // 4
- // 結(jié)果:1 2 6 8 4 7 5 3
面試題2:
- async function async1() {
- console.log('async1 start'); // 2
- await async2();
- console.log('async1 end'); // 6
- }
- async function async2() {
- console.log('async2'); // 3
- }
- console.log('script start'); // 1
- setTimeout(function () {
- console.log('setTimeout'); // 8
- }, 0)
- async1();
- new Promise(function (resolve) {
- console.log('promise1'); // 4
- resolve();
- }).then(function () {
- console.log('promise2'); // 7
- });
- console.log('script end'); // 5
- //結(jié)果:
- script start
- async1 start
- async2
- promise1
- script end
- async1 end
- promise2
- setTimeout
面試題3:
- console.log(1); // 1
- setTimeout(() => {
- console.log(2); // 6
- Promise.resolve().then(data => {
- console.log(3); // 7
- });
- });
- new Promise((resolve) => {
- resolve()
- console.log(4) // 2
- }).then(() => {
- console.log(5); // 4
- setTimeout(() => {
- console.log(6); // 8
- });
- }).then(() => console.log(7)) // 5
- console.log(8); // 3
- // 結(jié)果:1, 4, 8, 5, 7, 2, 3, 6
- 1, 4, 8 是同步 5, 7 是微任務(wù) 2 宏任務(wù) 3 微任務(wù) 6 宏任務(wù)
進(jìn)程/線程
* 核心答案 | 基礎(chǔ)知識要夯實
1) 進(jìn)程代表的是一個程序(瀏覽器開一個頁卡 (Tab頁) 就是一個進(jìn)程);
2) 線程是用來處理處理進(jìn)程中的具體事物的,如果一個程序中需要同時做好多事情,就需要開辟好多線程;
3) 一個線程同時只能做一件事情;
- 官方的說法
- 1) 進(jìn)程是cpu資源分配的最小單位(是能擁有資源和獨(dú)立運(yùn)行的最小單位)。
- 2) 線程是cpu調(diào)度的最小單位(線程是建立在進(jìn)程的基礎(chǔ)上的一次程序運(yùn)行單位,一個進(jìn)程中可以有多個線程)。
瀏覽器是多線程的
* 核心答案 | 基礎(chǔ)知識要夯實
1) 瀏覽器是多進(jìn)程的;
2) 瀏覽器之所以能夠運(yùn)行,是因為系統(tǒng)給它的進(jìn)程分配了資源(cpu、內(nèi)存);
3) 簡單點(diǎn)理解,每打開一個Tab頁,就相當(dāng)于創(chuàng)建了一個獨(dú)立的瀏覽器進(jìn)程;
那么接下來看看它都包含了哪些線程(列舉一些主要常駐線程)
GUI渲染線程
1) 負(fù)責(zé)渲染瀏覽器界面,解析HTML,CSS,構(gòu)建DOM樹和RenderObject樹,布局和繪制等。
2) 當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時,該線程就會執(zhí)行。
3) 注意,GUI渲染線程與JS引擎線程是互斥的,當(dāng)JS引擎執(zhí)行時GUI線程會被掛起(相當(dāng)于被凍結(jié)了),GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執(zhí)行。
JS引擎線程
也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎)
1) JS引擎線程負(fù)責(zé)解析Javascript腳本,運(yùn)行代碼。
2) JS引擎一直等待著任務(wù)隊列中任務(wù)的到來,然后加以處理,一個Tab頁(renderer進(jìn)程)中無論什么時候都只有一個JS線程在運(yùn)行JS程序。
3) 同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞。
JS中的單線程異步編程
* 核心答案 | 基礎(chǔ)知識要夯實
JS是單線程的:瀏覽器只分配一個線程用來渲染JS代碼。
1、JS中的代碼大部分都是“同步編程”:上面的任務(wù)沒有處理完成,下面的任務(wù)是無法處理的。
2?但是JS中利用瀏覽器的多線程機(jī)制,可以規(guī)劃出“異步編程”效果。
- 定時器
- ajax/Fetch/跨域 (HTTP網(wǎng)絡(luò)請求)
- 事件綁定
- Promise中有也有異步編程
- Generator / yield
- async / await
計算程序執(zhí)行的時間(預(yù)估)
1)運(yùn)行監(jiān)控 console.time/timeEnd(受當(dāng)前電腦運(yùn)行環(huán)境的影響)
2)大O表示法(提前預(yù)估)
- console.time('AAA');
- for (let i = 0; i < 99999999; i++) {}
- console.timeEnd('AAA');
真實項目中應(yīng)該避免死循環(huán) (重要)
- while (true) {}
- console.log('OK'); // 不執(zhí)行:上述的死循環(huán)一直占用這“JS渲染線程”,線程空閑不下來,就處理不了其他的事情
定時器的異步編程
1)設(shè)置定時器任務(wù)是同步的
2)“間隔interval這么長時間,執(zhí)行定時器綁定的函數(shù)” 這個任務(wù)是異步的
3)遇到異步任務(wù),瀏覽器不會等待它執(zhí)行完,則繼續(xù)渲染下面的代碼;當(dāng)?shù)鹊较旅娲a運(yùn)行完,時間也到達(dá)了執(zhí)行的條件,才會把異步任務(wù)執(zhí)行;
- setTimeout(() => {
- console.log("OK"); //2
- }, 1000);
- console.log('NO'); //1
interval設(shè)置為零也不是立即執(zhí)行,而是瀏覽器都有“最快反應(yīng)時間(谷歌:5~6ms IE:13~17ms)”,設(shè)置為零,最快也需要等到5~6ms左右
- setTimeout(() => {
- console.log('OK'); //2
- }, 0);
- console.log('NO'); //1
異步編程例子一:
- setTimeout(() => {
- console.log(1);
- }, 20);
- console.log(2);
- setTimeout(() => {
- console.log(3);
- }, 10);
- console.log(4);
- console.time('AA');
- for (let i = 0; i < 90000000; i++) {
- // do soming
- }
- console.timeEnd('AA'); //=>AA: 79ms 左右
- console.log(5);
- setTimeout(() => {
- console.log(6);
- }, 8);
- console.log(7);
- setTimeout(() => {
- console.log(8);
- }, 15);
- console.log(9);
- // 結(jié)果:2,4,5,7,9,3,1,6,8
畫圖分析:( 有圖有真相 )
執(zhí)行順序:同步任務(wù) —> 微任務(wù) —> 宏任務(wù) (微任務(wù)、宏任務(wù)在EventQueue)
- 細(xì)節(jié)點(diǎn)
- 當(dāng)棧中的“同步任務(wù)”或者其它任務(wù)沒有執(zhí)行完之前,JS渲染線程不會空閑下來,些時哪怕定時器已經(jīng)到達(dá)指定時間,也不會執(zhí)行的。 “JS是單線程的,一次只能做一件事情” => 定時器設(shè)定的等待時間是最快觸發(fā)執(zhí)行的時間,很多時候,到時間不一定會執(zhí)行,只有JS渲染線程空閑下來才會執(zhí)行。
本文名稱:JS基礎(chǔ)進(jìn)階- 同步異步編程和EventLoop底層機(jī)制
文章分享:http://fisionsoft.com.cn/article/codhhpc.html


咨詢
建站咨詢
