欧美1区2区3区激情无套,两个女人互添下身视频在线观看,久久av无码精品人妻系列,久久精品噜噜噜成人,末发育娇小性色xxxx

前端學(xué)習(xí)17 事件循環(huán)(Event Loop)機(jī)制

JavaScript作為一門(mén)單線(xiàn)程語(yǔ)言,卻能夠高效處理異步任務(wù),這一特性使其在處理網(wǎng)絡(luò)請(qǐng)求、用戶(hù)交互等場(chǎng)景下表現(xiàn)出色。而這一切的背后,都離不開(kāi)Event Loop(事件循環(huán))這一核心機(jī)制。

1.JavaScript的單線(xiàn)程

JavaScript是一門(mén)單線(xiàn)程語(yǔ)言,這意味著它只有一個(gè)主線(xiàn)程用于執(zhí)行代碼。這一設(shè)計(jì)決策主要是為了簡(jiǎn)化DOM操作的復(fù)雜性,避免多線(xiàn)程可能導(dǎo)致的并發(fā)問(wèn)題。然而,單線(xiàn)程也帶來(lái)了一個(gè)明顯的問(wèn)題:如果某個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)導(dǎo)致整個(gè)應(yīng)用"卡住",無(wú)法響應(yīng)用戶(hù)交互。

為了解決這個(gè)問(wèn)題,JavaScript引入了異步編程模型,而Event Loop就是這個(gè)模型的核心機(jī)制。

1.1 核心組件

JavaScript運(yùn)行時(shí)環(huán)境主要由以下幾個(gè)部分組成:

  • 調(diào)用棧(Call Stack):用于追蹤函數(shù)調(diào)用的棧結(jié)構(gòu),記錄當(dāng)前執(zhí)行的代碼位置。
  • 堆(Heap):用于存儲(chǔ)對(duì)象、數(shù)組等復(fù)雜的數(shù)據(jù)機(jī)構(gòu)的內(nèi)存區(qū)域
  • 任務(wù)隊(duì)列(Task Queues):存儲(chǔ)待執(zhí)行的回調(diào)函數(shù) 宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列
  • Web API/Node API:由運(yùn)行環(huán)境(瀏覽器/Node.js)提供的API,如定時(shí)器、網(wǎng)絡(luò)請(qǐng)求等

而是事件循環(huán)(Event Loop):協(xié)調(diào)調(diào)用棧和任務(wù)隊(duì)列之間的關(guān)系

1.2 調(diào)用棧

調(diào)用棧是一種LIFO(后進(jìn)先出)的數(shù)據(jù)結(jié)構(gòu),用于跟蹤代碼的執(zhí)行位置。當(dāng)調(diào)用一個(gè)函數(shù)時(shí),會(huì)將其壓入棧頂;當(dāng)函數(shù)執(zhí)行完畢,會(huì)從棧頂彈出。

function multiply(a, b) {
  return a * b;
}

function square(n) {
  return multiply(n, n);
}

function printSquare(n) {
  const result = square(n);
  console.log(result);
}

printSquare(5);

  1. 將printSquare(5)壓入棧
  2. 在printSquare內(nèi)部,將square(5)壓入棧
  3. 在square內(nèi)部,將multiply(5, 5)壓入棧
  4. multiply計(jì)算結(jié)果并返回,從棧中彈出
  5. square獲得結(jié)果并返回,從棧中彈出
  6. printSquare打印結(jié)果并結(jié)束,從棧中彈出

此時(shí),調(diào)用棧為空,標(biāo)志著同步代碼執(zhí)行完畢。

2. 事件循環(huán)核心機(jī)制

2.1 事件循環(huán)流程

  1. 執(zhí)行同步代碼,這些代碼會(huì)立即進(jìn)入調(diào)用棧執(zhí)行
  2. 調(diào)用棧清空后,檢查微任務(wù)隊(duì)列,依次執(zhí)行所有微任務(wù)
  3. 微任務(wù)隊(duì)列清空后,取出一個(gè)宏任務(wù)執(zhí)行
  4. 宏任務(wù)執(zhí)行完畢后,再次檢查微任務(wù)隊(duì)列,執(zhí)行所有微任務(wù)
  5. 重復(fù)步驟3和4,形成一個(gè)循環(huán)

2.2 宏任務(wù)(Macrotask)和微任務(wù)(Microtask)

理解宏任務(wù)(Macrotask)和微任務(wù)(Microtask)的區(qū)別是掌握事件循環(huán)的關(guān)鍵。

宏任務(wù)(Macrotask)包括:

  • setTimeout和setInterval回調(diào)
  • setImmediate回調(diào)(Node.js環(huán)境)
  • I/O操作回調(diào)
  • UI交互事件
  • requestAnimationFrame(瀏覽器環(huán)境)
  • MessageChannel回調(diào)

微任務(wù)(Microtask)包括:

  • Promise的then、catchfinally回調(diào)
  • queueMicrotask回調(diào)
  • MutationObserver回調(diào)(瀏覽器環(huán)境)
  • process.nextTick回調(diào)(Node.js環(huán)境,優(yōu)先級(jí)高于其他微任務(wù))

微任務(wù)優(yōu)先級(jí)高于宏任務(wù),即當(dāng)前宏任務(wù)執(zhí)行完后,會(huì)先清空微任務(wù)隊(duì)列,再執(zhí)行下一個(gè)宏任務(wù)。

console.log('1. 同步代碼開(kāi)始');

setTimeout(() => {
  console.log('2. 宏任務(wù)(setTimeout回調(diào))');
  
  new Promise(resolve => {
    console.log('3. 宏任務(wù)中的同步代碼');
    resolve();
  }).then(() => {
    console.log('4. 宏任務(wù)中的微任務(wù)');
  });
}, 0);

new Promise(resolve => {
  console.log('5. 同步代碼中的Promise');
  resolve();
}).then(() => {
  console.log('6. 微任務(wù)');
});

console.log('7. 同步代碼結(jié)束');

輸出順序?yàn)椋?/p>

  • 1. 同步代碼開(kāi)始
  • 5. 同步代碼中的Promise
  • 7. 同步代碼結(jié)束
  • 6. 微任務(wù)
  • 2. 宏任務(wù)(setTimeout回調(diào))
  • 3. 宏任務(wù)中的同步代碼
  • 4. 宏任務(wù)中的微任務(wù)

執(zhí)行過(guò)程分析:

  • 首先執(zhí)行同步代碼,輸出"1. 同步代碼開(kāi)始"
  • 遇到setTimeout,將其回調(diào)放入宏任務(wù)隊(duì)列
  • 遇到Promise構(gòu)造函數(shù),其內(nèi)部代碼是同步執(zhí)行的,輸出"5. 同步代碼中的Promise"
  • 將Promise的then回調(diào)放入微任務(wù)隊(duì)列
  • 輸出"7. 同步代碼結(jié)束"
  • 同步代碼執(zhí)行完畢,檢查微任務(wù)隊(duì)列,執(zhí)行Promise的then回調(diào),輸出"6. 微任務(wù)"
  • 微任務(wù)隊(duì)列清空,從宏任務(wù)隊(duì)列取出setTimeout回調(diào)執(zhí)行
  • 在setTimeout回調(diào)中,輸出"2. 宏任務(wù)(setTimeout回調(diào))"
  • 遇到新的Promise,輸出"3. 宏任務(wù)中的同步代碼"
  • 將新Promise的then回調(diào)放入微任務(wù)隊(duì)列
  • setTimeout回調(diào)執(zhí)行完畢,檢查微任務(wù)隊(duì)列,執(zhí)行Promise的then回調(diào),輸出"4. 宏任務(wù)中的微任務(wù)"

3.瀏覽器的事件循環(huán)

瀏覽器環(huán)境中的事件循環(huán)有其獨(dú)特的特性,特別是與渲染管道的交互。

在瀏覽器環(huán)境中,渲染步驟(樣式計(jì)算、布局、繪制等)通常發(fā)生在宏任務(wù)之間,且在所有微任務(wù)執(zhí)行完畢之后。這意味著,如果你想在下一次渲染前操作DOM,應(yīng)該使用微任務(wù)或requestAnimationFrame(用于在下一次瀏覽器重繪之前執(zhí)行指定的回調(diào)函數(shù)。它的作用是告訴瀏覽器我們希望執(zhí)行一段動(dòng)畫(huà),并在動(dòng)畫(huà)執(zhí)行時(shí)進(jìn)行優(yōu)化,以獲得更流暢的效果)。

// 不建議的寫(xiě)法:可能導(dǎo)致多次不必要的重排
button.addEventListener('click', () => {
  box.style.width = '100px';
  box.style.height = '100px';
  box.style.margin = '20px';
});

// 優(yōu)化的寫(xiě)法:所有DOM操作合并到下一幀執(zhí)行
button.addEventListener('click', () => {
  requestAnimationFrame(() => {
    box.style.width = '100px';
    box.style.height = '100px';
    box.style.margin = '20px';
  });
});

瀏覽器環(huán)境中的setTimeout和setInterval并不保證在指定時(shí)間后精確執(zhí)行,只能保證在指定時(shí)間后將回調(diào)膠乳宏任務(wù)隊(duì)列。如果調(diào)用?;蚱渌耆蝿?wù)占用主線(xiàn)程,定時(shí)器回調(diào)會(huì)被延遲執(zhí)行。

此外,大多數(shù)瀏覽器對(duì)不活躍標(biāo)簽頁(yè)中的定時(shí)器有最小間隔限制(通常為1000ms),以節(jié)省系統(tǒng)資源。

4.事件循環(huán)與異步模式

4.1 回調(diào)地獄

// 回調(diào)地獄示例
getData(function(a) {
  getMoreData(a, function(b) {
    getEvenMoreData(b, function(c) {
      getFinalData(c, function(result) {
        console.log(result);
      }, handleError);
    }, handleError);
  }, handleError);
}, handleError);

解決方案:

1、使用Promise鏈:將嵌套回調(diào)轉(zhuǎn)換為扁平的鏈?zhǔn)秸{(diào)用

getData()
  .then(a => getMoreData(a))
  .then(b => getEvenMoreData(b))
  .then(c => getFinalData(c))
  .then(result => console.log(result))
  .catch(handleError);

2、使用async/await:使異步代碼看起來(lái)像同步代碼

async function fetchAllData() {
  try {
    const a = await getData();
    const b = await getMoreData(a);
    const c = await getEvenMoreData(b);
    const result = await getFinalData(c);
    console.log(result);
  } catch (error) {
    handleError(error);
  }
}

fetchAllData();

全部評(píng)論

相關(guān)推薦

點(diǎn)贊 評(píng)論 收藏
分享
評(píng)論
2
2
分享

創(chuàng)作者周榜

更多
??途W(wǎng)
牛客企業(yè)服務(wù)