解讀JavaScript中的事件循環(huán)
Sep 03, 2023 pm 01:17 PM您可能已經(jīng)知道 JavaScript 是單執(zhí)行緒程式語(yǔ)言。這意味著 JavaScript 在 Web 瀏覽器或 Node.js 中的單一主執(zhí)行緒上運(yùn)行。在單一主執(zhí)行緒上運(yùn)行意味著一次只運(yùn)行一段 JavaScript 程式碼。
JavaScript 中的事件循環(huán)在決定程式碼如何在主執(zhí)行緒上執(zhí)行方面發(fā)揮著重要作用。事件循環(huán)負(fù)責(zé)一些事情,例如程式碼的執(zhí)行以及事件的收集和處理。它也處理任何排隊(duì)子任務(wù)的執(zhí)行。
在本教程中,您將學(xué)習(xí) JavaScript 中事件循環(huán)的基礎(chǔ)知識(shí)。
事件循環(huán)如何運(yùn)作
為了理解事件循環(huán)的工作原理,您需要了解三個(gè)重要術(shù)語(yǔ)。
堆疊
呼叫堆疊只是追蹤函數(shù)執(zhí)行上下文的函數(shù)呼叫堆疊。該堆疊遵循後進(jìn)先出 (LIFO) 原則,這意味著最近調(diào)用的函數(shù)將是第一個(gè)執(zhí)行的函數(shù)。
隊(duì)列
佇列包含一系列由 JavaScript 執(zhí)行的任務(wù)。該佇列中的任務(wù)可能會(huì)導(dǎo)致呼叫函數(shù),然後將其放入堆疊中。僅當(dāng)堆疊為空時(shí)才開始佇列的處理。隊(duì)列中的項(xiàng)目遵循先進(jìn)先出 (FIFO) 原則。這意味著最舊的任務(wù)將首先完成。
堆
堆基本上是儲(chǔ)存和分配物件的一大塊記憶體區(qū)域。它的主要目的是儲(chǔ)存堆疊中的函數(shù)可能使用的資料。
基本上,JavaScript 是單執(zhí)行緒的,一次執(zhí)行一個(gè)函數(shù)。這個(gè)單一函數(shù)被放置在堆疊上。該函數(shù)還可以包含其他巢狀函數(shù),這些函數(shù)將放置在堆疊中的上方。堆疊遵循 LIFO 原則,因此最近呼叫的巢狀函數(shù)將首先執(zhí)行。
API 請(qǐng)求或計(jì)時(shí)器等非同步任務(wù)將會(huì)新增至佇列以便稍後執(zhí)行。 JavaScript 引擎在空閒時(shí)開始執(zhí)行佇列中的任務(wù)。
考慮以下範(fàn)例:
function helloWorld() { console.log("Hello, World!"); } function helloPerson(name) { console.log(`Hello, ${name}!`); } function helloTeam() { console.log("Hello, Team!"); helloPerson("Monty"); } function byeWorld() { console.log("Bye, World!"); } helloWorld(); helloTeam(); byeWorld(); /* Outputs: Hello, World! Hello, Team! Hello, Monty! Bye, World! */
讓我們看看如果運(yùn)行上面的程式碼,堆疊和佇列會(huì)是什麼樣子。
呼叫 helloWorld()
函數(shù)並將其放入堆疊中。它記錄 Hello, World! 完成其執(zhí)行,因此它被從堆疊中取出。接下來呼叫 helloTeam()
函數(shù)並將其放入堆疊中。在執(zhí)行過程中,我們記錄 Hello, Team! 並呼叫 helloPerson()
。 helloTeam()
的執(zhí)行還沒完成,所以它停留在堆疊上,而 helloPerson()
則放在它上面。
後進(jìn)先出原則規(guī)定 helloPerson()
現(xiàn)在執(zhí)行。這會(huì)將 Hello, Monty! 記錄到控制臺(tái),從而完成其執(zhí)行,並且 helloPerson()
將從堆疊中取出。之後 helloTeam()
函數(shù)就會(huì)出棧,我們最後到達(dá) byeWorld()
。它會(huì)記錄再見,世界! ,然後從堆疊中消失。
隊(duì)列一直是空的。
現(xiàn)在,考慮上述程式碼的細(xì)微變化:
function helloWorld() { console.log("Hello, World!"); } function helloPerson(name) { console.log(`Hello, ${name}!`); } function helloTeam() { console.log("Hello, Team!"); setTimeout(() => { helloPerson("Monty"); }, 0); } function byeWorld() { console.log("Bye, World!"); } helloWorld(); helloTeam(); byeWorld(); /* Outputs: Hello, World! Hello, Team! Bye, World! Hello, Monty! */
我們?cè)谶@裡所做的唯一更改是使用 setTimeout()
。但是,超時(shí)已設(shè)定為零。因此,我們期望 Hello, Monty! 在 Bye, World! 之前輸出。如果您了解事件循環(huán)的工作原理,您就會(huì)明白為什麼不會(huì)發(fā)生這種情況。 < /p>
當(dāng)helloTeam()
入堆疊時(shí),遇到setTimeout()
方法。但是,setTimeout()
中對(duì) helloPerson()
的呼叫會(huì)被放入佇列中,一旦沒有同步任務(wù)需要執(zhí)行,就會(huì)被執(zhí)行。
一旦對(duì) byeWorld()
的呼叫完成,事件循環(huán)將檢查佇列中是否有任何掛起的任務(wù),並找到對(duì) helloPerson()
的呼叫。此時(shí),它執(zhí)行該函數(shù)並將 Hello, Monty! 記錄到控制臺(tái)。
這表示您提供給 setTimeout()
的超時(shí)持續(xù)時(shí)間並不是回呼執(zhí)行的保證時(shí)間。這是執(zhí)行回調(diào)的最短時(shí)間。
保持我們的網(wǎng)頁(yè)回應(yīng)
JavaScript 的一個(gè)有趣的功能是它會(huì)執(zhí)行一個(gè)函數(shù)直到完成。這意味著只要函數(shù)在堆疊上,事件循環(huán)就無(wú)法處理佇列中的任何其他任務(wù)或執(zhí)行其他函數(shù)。
這可能會(huì)導(dǎo)致網(wǎng)頁(yè)“掛起”,因?yàn)樗鼰o(wú)法執(zhí)行其他操作,例如處理使用者輸入或進(jìn)行與 DOM 相關(guān)的更改。考慮以下範(fàn)例,我們?cè)谄渲胁檎医o定範(fàn)圍內(nèi)的素?cái)?shù)數(shù)量:
function isPrime(num) { if (num <= 1) { return false; } for (let i = 2; i <= Math.sqrt(num); i++) { if (num % i === 0) { return false; } } return true; } function listPrimesInRange(start, end) { const primes = []; for (let num = start; num <= end; num++) { if (isPrime(num)) { primes.push(num); } } return primes; }
在我們的 listPrimesInRange()
函數(shù)中,我們迭代從 start
到 end
的數(shù)字。對(duì)於每個(gè)數(shù)字,我們呼叫 isPrime()
函數(shù)來查看它是否是質(zhì)數(shù)。 isPrime()
函數(shù)本身有一個(gè)for
循環(huán),從2
到Math.sqrt(num)
來決定數(shù)字是否為素?cái)?shù)。
查找給定范圍內(nèi)的所有素?cái)?shù)可能需要一段時(shí)間,具體取決于您使用的值。當(dāng)瀏覽器進(jìn)行此計(jì)算時(shí),它無(wú)法執(zhí)行任何其他操作。這是因?yàn)?listPrimesInRange()
函數(shù)將保留在堆棧中,瀏覽器將無(wú)法執(zhí)行隊(duì)列中的任何其他任務(wù)。
現(xiàn)在,看一下以下函數(shù):
function listPrimesInRangeResponsively(start) { let next = start + 100,000; if (next > end) { next = end; } for (let num = start; num <= next; num++) { if (isPrime(num)) { primeNumbers.push(num); } if (num == next) { percentage = ((num - begin) * 100) / (end - begin); percentage = Math.floor(percentage); progress.innerText = `Progress ${percentage}%`; if (num != end) { setTimeout(() => { listPrimesInRangeResponsively(next + 1); }); } } if (num == end) { percentage = ((num - begin) * 100) / (end - begin); percentage = Math.floor(percentage); progress.innerText = `Progress ${percentage}%`; heading.innerText = `${primeNumbers.length - 1} Primes Found!`; console.log(primeNumbers); return primeNumbers; } } }
這一次,我們的函數(shù)僅在批量處理范圍時(shí)嘗試查找素?cái)?shù)。它通過遍歷所有數(shù)字但一次僅處理其中的 100,000 個(gè)來實(shí)現(xiàn)這一點(diǎn)。之后,它使用 setTimeout()
觸發(fā)對(duì)同一函數(shù)的下一次調(diào)用。
setTimeout()
被調(diào)用而沒有指定延遲時(shí),它會(huì)立即將回調(diào)函數(shù)添加到事件隊(duì)列中。
下一個(gè)調(diào)用將被放入隊(duì)列中,暫時(shí)清空堆棧以處理任何其他任務(wù)。之后,JavaScript 引擎開始在下一批 100,000 個(gè)數(shù)字中查找素?cái)?shù)。
嘗試單擊此頁(yè)面上的計(jì)算(卡?。?/strong>按鈕,您可能會(huì)收到一條消息,指出該網(wǎng)頁(yè)正在減慢您的瀏覽器速度,并建議您停止該腳本。 p>
另一方面,單擊計(jì)算(響應(yīng)式)按鈕仍將使網(wǎng)頁(yè)保持響應(yīng)式。
最終想法
在本教程中,我們了解了 JavaScript 中的事件循環(huán)以及它如何有效地執(zhí)行同步和異步代碼。事件循環(huán)使用隊(duì)列來跟蹤它必須執(zhí)行的任務(wù)。
由于 JavaScript 不斷執(zhí)行函數(shù)直至完成,因此進(jìn)行大量計(jì)算有時(shí)會(huì)“掛起”瀏覽器窗口。根據(jù)我們對(duì)事件循環(huán)的理解,我們可以重寫我們的函數(shù),以便它們批量進(jìn)行計(jì)算。這允許瀏覽器保持窗口對(duì)用戶的響應(yīng)。它還使我們能夠定期向用戶更新我們?cè)谟?jì)算中取得的進(jìn)展。
以上是解讀JavaScript中的事件循環(huán)的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁(yè)開發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)

WordPress導(dǎo)致服務(wù)器CPU使用率飆升的主要原因包括插件問題、數(shù)據(jù)庫(kù)查詢效率低、主題代碼質(zhì)量差或流量激增。 1.首先通過top、htop或控制面板工具確認(rèn)是否為WordPress引起的高負(fù)載;2.進(jìn)入故障排查模式逐步啟用插件排查性能瓶頸,使用QueryMonitor分析插件執(zhí)行情況並刪除或替換低效插件;3.安裝緩存插件、清理冗餘數(shù)據(jù)、分析慢查詢?nèi)照I以優(yōu)化數(shù)據(jù)庫(kù);4.檢查主題是否存在過度加載內(nèi)容、複雜查詢或缺乏緩存機(jī)制等問題,建議用標(biāo)準(zhǔn)主題測(cè)試對(duì)比並優(yōu)化代碼邏輯。按照上述步驟逐一排查可定位並解

MinifyingJavaScript文件可通過刪除空白、註釋和無(wú)用代碼來提升WordPress網(wǎng)站加載速度。 1.使用支持合併壓縮的緩存插件如W3TotalCache,在“Minify”選項(xiàng)中啟用並選擇壓縮模式;2.使用專用壓縮插件如FastVelocityMinify,提供更精細(xì)控制;3.手動(dòng)壓縮JS文件並通過FTP上傳,適用於熟悉開發(fā)工具的用戶。注意部分主題或插件腳本可能與壓縮功能衝突,啟用後需徹底測(cè)試網(wǎng)站功能。

優(yōu)化WordPress站點(diǎn)不依賴插件的方法包括:1.使用輕量級(jí)主題,如Astra或GeneratePress,避免功能堆砌的主題;2.手動(dòng)壓縮和合併CSS、JS文件,減少HTTP請(qǐng)求;3.上傳前優(yōu)化圖片,使用WebP格式並控製文件大小;4.配置.htaccess啟用瀏覽器緩存,並接入CDN提升靜態(tài)資源加載速度;5.限製文章修訂版本並定期清理數(shù)據(jù)庫(kù)冗餘數(shù)據(jù)。

防止評(píng)論垃圾信息最有效的方式是通過程序化手段自動(dòng)識(shí)別並攔截。 1.使用驗(yàn)證碼機(jī)制(如GooglereCAPTCHA或hCaptcha)可有效區(qū)分人類與機(jī)器人,尤其適合公眾網(wǎng)站;2.設(shè)置隱藏字段(Honeypot技術(shù)),利用機(jī)器人自動(dòng)填寫特性識(shí)別垃圾評(píng)論,不影響用戶體驗(yàn);3.檢查評(píng)論內(nèi)容關(guān)鍵詞黑名單,通過敏感詞匹配過濾垃圾信息,需注意避免誤判;4.判斷評(píng)論頻率與來源IP,限制單位時(shí)間內(nèi)的提交次數(shù)並建立黑名單;5.使用第三方反垃圾服務(wù)(如Akismet、Cloudflare)提升識(shí)別準(zhǔn)確性??筛鶕?jù)網(wǎng)站

TransientsAPI是WordPress中用於臨時(shí)存儲(chǔ)可自動(dòng)過期數(shù)據(jù)的內(nèi)置工具,其核心函數(shù)為set_transient、get_transient和delete_transient。相比OptionsAPI,transients支持設(shè)置生存時(shí)間(TTL),適合緩存API請(qǐng)求結(jié)果、複雜計(jì)算數(shù)據(jù)等場(chǎng)景。使用時(shí)需注意key命名唯一性與命名空間、緩存“懶刪除”機(jī)制及對(duì)象緩存環(huán)境下可能不持久的問題。典型應(yīng)用場(chǎng)景包括減少外部請(qǐng)求頻率、控制代碼執(zhí)行節(jié)奏和提升頁(yè)面加載性能。

在開發(fā)Gutenberg塊時(shí),正確enqueue資產(chǎn)的方法包括:1.使用register_block_type指定editor_script、editor_style和style的路徑;2.在functions.php或插件中通過wp_register_script和wp_register_style註冊(cè)資源,並設(shè)置正確的依賴和版本;3.配置構(gòu)建工具輸出合適的模塊格式,並確保路徑一致;4.通過add_theme_support或enqueue_block_assets控制前端樣式的加載邏輯,確保

要添加自定義用戶字段需根據(jù)平臺(tái)選擇擴(kuò)展方式並註意數(shù)據(jù)驗(yàn)證與權(quán)限控制。常見做法包括:1.利用數(shù)據(jù)庫(kù)額外表或鍵值對(duì)結(jié)構(gòu)存儲(chǔ)信息;2.在前端加入輸入框並與後端集成;3.對(duì)敏感數(shù)據(jù)進(jìn)行格式校驗(yàn)和訪問權(quán)限限制;4.更新接口及模板以支持新字段展示與編輯,同時(shí)兼顧移動(dòng)端適配和用戶體驗(yàn)。

在WordPress中添加自定義重寫規(guī)則的關(guān)鍵在於使用add_rewrite_rule函數(shù)並確保規(guī)則正確生效。 1.使用add_rewrite_rule註冊(cè)規(guī)則,格式為add_rewrite_rule($regex,$redirect,$after),其中$regex是正則表達(dá)式匹配URL,$redirect指定實(shí)際查詢,$after控制規(guī)則位置;2.需通過add_filter添加自定義查詢變量;3.修改後必須刷新固定鏈接設(shè)置;4.建議將規(guī)則放在'top'以避免衝突;5.可藉助插件查看當(dāng)前規(guī)則便於
