欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS面試高頻單線程與事件循環(huán)深入解析

 更新時(shí)間:2023年10月24日 09:13:29   作者:千年老妖  
JavaScript是一種單線程語(yǔ)言,它在任何給定時(shí)間只能執(zhí)行一個(gè)任務(wù),然而js確能夠處理異步操作,這得益于其事件循環(huán)(Event Loop)機(jī)制,今天這篇文章帶領(lǐng)大家深入理解JavaScript單線程特性,以及講解事件循環(huán)和js多線程知識(shí)

一、背景:為什么JS是單線程?

在最開(kāi)始設(shè)計(jì)中,JS的主要用途是處理瀏覽器中的用戶界面事件。由于JS交互直接進(jìn)行DOM操作,如果允許多線程對(duì)DOM進(jìn)行并行操作,可能會(huì)導(dǎo)致競(jìng)態(tài)條件,例如一個(gè)線程正在讀取節(jié)點(diǎn),而另一個(gè)線程正在修改它。這將導(dǎo)致程序的不可預(yù)測(cè)性,因此,JS被設(shè)計(jì)為單線程語(yǔ)言,以避免這種復(fù)雜性。

二、事件循環(huán)

事件循環(huán)的核心思想是:JS引擎首先執(zhí)行當(dāng)前的同步任務(wù),然后檢查任務(wù)隊(duì)列(Task Queue)中是否有待處理的異步任務(wù)。如果有,它會(huì)按照順序?qū)⑦@些異步任務(wù)添加到執(zhí)行隊(duì)列,并在當(dāng)前任務(wù)執(zhí)行完畢后依次執(zhí)行它們。在這個(gè)過(guò)程中,宏任務(wù)和微任務(wù)是兩種不同類型的異步任務(wù),它們?cè)谑录h(huán)中的處理方式有所不同。

2.1 宏任務(wù)(MacroTask)

宏任務(wù)是指那些需要在下一個(gè)事件循環(huán)周期執(zhí)行的任務(wù)。常見(jiàn)的宏任務(wù)包括:

  • setTimeout
  • setInterval
  • setImmediate(Node.js 獨(dú)有)
  • I/O 操作(Node.js 獨(dú)有)
  • UI 渲染(瀏覽器獨(dú)有)

當(dāng)事件循環(huán)執(zhí)行到一個(gè)宏任務(wù)時(shí),它會(huì)將該任務(wù)添加到宏任務(wù)隊(duì)列中。在當(dāng)前事件循環(huán)周期結(jié)束時(shí),JS引擎會(huì)檢查宏任務(wù)隊(duì)列,并將隊(duì)列中的任務(wù)依次執(zhí)行。

2.2 微任務(wù)(MicroTask)

微任務(wù)是指那些在當(dāng)前事件循環(huán)周期內(nèi)執(zhí)行的任務(wù)。常見(jiàn)的微任務(wù)包括:

  • Promise.then 和 Promise.catch
  • async/await(實(shí)際上是基于 Promise 的語(yǔ)法糖)
  • process.nextTick(Node.js 獨(dú)有)
  • MutationObserver(瀏覽器獨(dú)有)

當(dāng)事件循環(huán)執(zhí)行到一個(gè)微任務(wù)時(shí),它會(huì)將該任務(wù)添加到微任務(wù)隊(duì)列中。與宏任務(wù)不同,微任務(wù)會(huì)在當(dāng)前事件循環(huán)周期內(nèi)立即執(zhí)行,而不是等待下一個(gè)事件循環(huán)周期。

2.3 事件循環(huán)處理宏任務(wù)和微任務(wù)的順序

  • 從宏任務(wù)隊(duì)列中取出一個(gè)任務(wù)并執(zhí)行。
  • 檢查微任務(wù)隊(duì)列,如果有任務(wù),則依次執(zhí)行所有微任務(wù)。
  • 檢查宏任務(wù)隊(duì)列,如果有任務(wù),則返回步驟1,否則等待新任務(wù)。

這意味著,在一個(gè)事件循環(huán)周期中,微任務(wù)會(huì)在宏任務(wù)之間執(zhí)行。換句話說(shuō),當(dāng)一個(gè)宏任務(wù)執(zhí)行完畢后,JS引擎會(huì)檢查微任務(wù)隊(duì)列,并在執(zhí)行下一個(gè)宏任務(wù)之前執(zhí)行所有的微任務(wù)。

下面是一個(gè)簡(jiǎn)單的示例,展示了宏任務(wù)和微任務(wù)在事件循環(huán)中的執(zhí)行順序:

console.log('Start'); // 同步任務(wù)
setTimeout(() => {
    console.log('setTimeout'); // 宏任務(wù)
}, 0);
Promise.resolve().then(() => {
    console.log('Promise'); // 微任務(wù)
});
console.log('End'); // 同步任務(wù)

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

Start
End
Promise
setTimeout

這是因?yàn)樵趫?zhí)行到 setTimeout 時(shí),它被添加到宏任務(wù)隊(duì)列中。而在執(zhí)行到 Promise 時(shí),它被添加到微任務(wù)隊(duì)列中。在當(dāng)前事件循環(huán)周期結(jié)束之前,JS引擎會(huì)先執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù),然后再執(zhí)行宏任務(wù)隊(duì)列中的任務(wù)。

事件循環(huán)是JavaScript運(yùn)行時(shí)環(huán)境的核心組件,負(fù)責(zé)處理宏任務(wù)和微任務(wù)。了解宏任務(wù)和微任務(wù)在事件循環(huán)中的執(zhí)行順序,有助于我們更好地理解和編寫(xiě)異步代碼。

三、 異步編程

  • 回調(diào)函數(shù):最基本的異步編程模型,將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)異步操作完成時(shí),回調(diào)函數(shù)被執(zhí)行。
function downloadFile(url, callback) {
    // 模擬異步操作
    setTimeout(() => {
        console.log(`Downloaded file from ${url}`);
        callback();
    }, 2000);
}
downloadFile('https://example.com/file.txt', function() {
    console.log('File download complete');
});
  • Promise:Promise是一種更高級(jí)的異步編程模型,它表示一個(gè)異步操作的最終結(jié)果。Promise有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。?/li>
function downloadFile(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(`Downloaded file from ${url}`);
            resolve();
        }, 2000);
    });
}
downloadFile('https://example.com/file.txt')
    .then(() => {
        console.log('File download complete');
    });
  • async/await:async/await是基于Promise的一種更簡(jiǎn)潔的異步編程模型。通過(guò)使用async關(guān)鍵字聲明一個(gè)函數(shù)為異步函數(shù),然后在函數(shù)內(nèi)部使用await關(guān)鍵字等待Promise的結(jié)果。
async function downloadFile(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(`Downloaded file from ${url}`);
            resolve();
        }, 2000);
    });
}
(async () => {
    await downloadFile('https://example.com/file.txt');
    console.log('File download complete');
})();

三、單線程的優(yōu)缺點(diǎn)

3.1 優(yōu)點(diǎn)

  • 避免了多線程下的復(fù)雜性,如死鎖。
  • 簡(jiǎn)化了異步操作,使得異步編程更易于構(gòu)建和理解。

3.2 缺點(diǎn)

  • 長(zhǎng)時(shí)間運(yùn)行的任務(wù)可能會(huì)阻塞線程,影響用戶體驗(yàn)。
  • 無(wú)法充分利用多核CPU的計(jì)算能力。

四、實(shí)現(xiàn)多線程的方法

盡管JS是單線程,但我們可以通過(guò)Web Workers在瀏覽器中創(chuàng)建多個(gè)線程。Web Workers運(yùn)行在后臺(tái)線程中,不影響主線程,它們之間通過(guò)postMessage來(lái)進(jìn)行通信。

4.1 Web Workers

這是一個(gè)簡(jiǎn)單的Web Worker示例,演示了多個(gè)進(jìn)程之間的通信:

// main.js
const worker = new Worker('worker.js');
worker.postMessage('Hello, Worker!');
worker.onmessage = function(event) {
    console.log('Message from worker:', event.data);
};
// worker.js
self.onmessage = function(event) {
    console.log('Message from main thread:', event.data);
    self.postMessage('Hello, Main Thread!');
};

4.2 SharedArrayBuffer與Atomics

為了實(shí)現(xiàn)更高級(jí)的多線程編程,JS引入了SharedArrayBuffer和Atomics對(duì)象。SharedArrayBuffer允許多個(gè)Web Workers共享同一塊內(nèi)存,而Atomics對(duì)象提供了一組原子操作,確保在多線程環(huán)境下對(duì)共享內(nèi)存的操作是安全的。

以下是一個(gè)使用SharedArrayBuffer和Atomics的示例:

// main.js
const worker = new Worker('worker.js');
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
worker.postMessage(sharedBuffer);
Atomics.store(sharedArray, 0, 1);
console.log('Main thread set value:', sharedArray[0]);
worker.onmessage = function(event) {
    console.log('Message from worker:', event.data);
};
// worker.js
self.onmessage = function(event) {
    const sharedBuffer = event.data;
    const sharedArray = new Int32Array(sharedBuffer);
    console.log('Worker thread initial value:', sharedArray[0]);
    Atomics.add(sharedArray, 0, 1);
    console.log('Worker thread updated value:', sharedArray[0]);
    self.postMessage('SharedArrayBuffer updated');
};

4.3 使用Web Workers的注意事項(xiàng)

  • Web Workers無(wú)法訪問(wèn)主線程的全局變量和函數(shù)。
  • Web Workers無(wú)法直接操作DOM。
  • 通信開(kāi)銷(xiāo):Web Workers之間的通信需要通過(guò)postMessage和onmessage事件進(jìn)行,這會(huì)帶來(lái)一定的性能開(kāi)銷(xiāo)。

總結(jié)

JS的單線程特性使得編程模型簡(jiǎn)單易懂,但也帶來(lái)了一些限制。通過(guò)使用事件循環(huán)、異步編程模型和Web Workers,我們可以在很大程度上克服這些限制,進(jìn)而實(shí)現(xiàn)高性能的Web應(yīng)用。

以上就是JS面試高頻單線程與事件循環(huán)深入解析的詳細(xì)內(nèi)容,更多關(guān)于JS單線程事件循環(huán)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序分包加載的實(shí)現(xiàn)代碼

    微信小程序分包加載的實(shí)現(xiàn)代碼

    分包加載是一種小程序優(yōu)化技術(shù),將小程序不同功能的代碼,分別打包成不同的子包,在構(gòu)建時(shí)打包成不同的分包,用戶在使用時(shí)按需進(jìn)行加載,在構(gòu)建小程序分包項(xiàng)目時(shí),構(gòu)建會(huì)輸出一個(gè)或多個(gè)分包,這篇文章主要介紹了微信小程序---分包加載,需要的朋友可以參考下
    2024-07-07
  • 微信小程序倒計(jì)時(shí)功能實(shí)例代碼

    微信小程序倒計(jì)時(shí)功能實(shí)例代碼

    這篇文章主要介紹了微信小程序倒計(jì)時(shí)功能實(shí)例代碼,當(dāng)單擊按鈕彈出一個(gè)半透明的彈出層,在規(guī)定時(shí)間內(nèi)激活關(guān)閉按鈕,關(guān)閉彈出層。需要的朋友可以參考下
    2018-07-07
  • js實(shí)現(xiàn)的八點(diǎn)拖動(dòng)修改div大小的代碼

    js實(shí)現(xiàn)的八點(diǎn)拖動(dòng)修改div大小的代碼

    八點(diǎn)改變div大小的實(shí)現(xiàn)代碼,代碼相對(duì)來(lái)說(shuō)并不多,需要的朋友可以參考下。
    2010-02-02
  • JS路由跳轉(zhuǎn)的簡(jiǎn)單實(shí)現(xiàn)代碼

    JS路由跳轉(zhuǎn)的簡(jiǎn)單實(shí)現(xiàn)代碼

    本文給大家分享一個(gè)簡(jiǎn)單的js路由跳轉(zhuǎn)功能,非常不錯(cuò),需要的朋友參考下吧
    2017-09-09
  • JavaScript檢測(cè)瀏覽器cookie是否已經(jīng)啟動(dòng)的方法

    JavaScript檢測(cè)瀏覽器cookie是否已經(jīng)啟動(dòng)的方法

    這篇文章主要介紹了JavaScript檢測(cè)瀏覽器cookie是否已經(jīng)啟動(dòng)的方法,實(shí)例分析了javascript操作cookie的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • 最新評(píng)論