国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
關(guān)鍵要點(diǎn)
什么是事件循環(huán)?
半無(wú)限循環(huán)
回調(diào)隊(duì)列
使用 async/await 的事件循環(huán)
更進(jìn)一步
事件循環(huán)階段
逐階段演示
線程池
總結(jié)
process.nextTick() 與 setImmediate()
結(jié)論
關(guān)于 Node.js 事件循環(huán)的常見(jiàn)問(wèn)題
首頁(yè) web前端 js教程 Node.js事件循環(huán):開(kāi)發(fā)人員的概念和代碼指南

Node.js事件循環(huán):開(kāi)發(fā)人員的概念和代碼指南

Feb 12, 2025 am 08:36 AM

Node.js 的異步編程:深入理解事件循環(huán)

The Node.js Event Loop: A Developer's Guide to Concepts & Code

異步編程在任何編程語(yǔ)言中都極具挑戰(zhàn)性。并發(fā)、并行和死鎖等概念讓即使是最資深的工程師也感到棘手。異步執(zhí)行的代碼難以預(yù)測(cè),出現(xiàn)bug時(shí)也難以追蹤。然而,這個(gè)問(wèn)題是不可避免的,因?yàn)楝F(xiàn)代計(jì)算擁有多核處理器。每個(gè)CPU內(nèi)核都有其熱限制,單核性能提升已達(dá)到瓶頸。這促使開(kāi)發(fā)者編寫高效的代碼,充分利用硬件資源。

JavaScript 是單線程的,但這是否限制了 Node.js 利用現(xiàn)代架構(gòu)的能力呢?最大的挑戰(zhàn)之一是處理多線程的固有復(fù)雜性。創(chuàng)建新線程和管理線程間的上下文切換代價(jià)高昂。操作系統(tǒng)和程序員都需要付出大量努力才能提供一個(gè)處理眾多邊緣情況的解決方案。本文將闡述 Node.js 如何通過(guò)事件循環(huán)來(lái)解決這個(gè)難題,深入探討 Node.js 事件循環(huán)的各個(gè)方面并演示其工作原理。事件循環(huán)是 Node.js 的殺手級(jí)特性之一,因?yàn)樗砸环N全新的方式解決了這個(gè)棘手的問(wèn)題。

關(guān)鍵要點(diǎn)

  • Node.js 事件循環(huán)是一個(gè)單線程、非阻塞和異步并發(fā)的循環(huán),允許高效處理多個(gè)任務(wù),而無(wú)需等待每個(gè)任務(wù)完成。這使得同時(shí)處理多個(gè) Web 請(qǐng)求成為可能。
  • 事件循環(huán)是半無(wú)限的,這意味著如果調(diào)用?;蚧卣{(diào)隊(duì)列為空,它可以退出。該循環(huán)負(fù)責(zé)輪詢操作系統(tǒng)以獲取來(lái)自傳入連接的回調(diào)。
  • 事件循環(huán)在多個(gè)階段運(yùn)行:時(shí)間戳更新、循環(huán)活躍性檢查、定時(shí)器執(zhí)行、待處理回調(diào)執(zhí)行、空閑處理程序執(zhí)行、準(zhǔn)備 setImmediate 回調(diào)執(zhí)行的句柄、計(jì)算輪詢超時(shí)、阻塞 I/O、檢查句柄回調(diào)執(zhí)行、關(guān)閉回調(diào)執(zhí)行以及迭代結(jié)束。
  • Node.js 利用兩個(gè)主要部分:V8 JavaScript 引擎和 libuv。網(wǎng)絡(luò) I/O、文件 I/O 和 DNS 查詢通過(guò) libuv 進(jìn)行。線程池中可用于這些任務(wù)的線程數(shù)量有限,可以通過(guò) UV_THREADPOOL_SIZE 環(huán)境變量進(jìn)行設(shè)置。
  • 在每個(gè)階段結(jié)束時(shí),循環(huán)執(zhí)行 process.nextTick() 回調(diào),它不是事件循環(huán)的一部分,因?yàn)樗诿總€(gè)階段結(jié)束時(shí)運(yùn)行。setImmediate() 回調(diào)是整個(gè)事件循環(huán)的一部分,因此它并不像名稱暗示的那樣立即執(zhí)行。一般建議使用 setImmediate()。

什么是事件循環(huán)?

事件循環(huán)是一個(gè)單線程、非阻塞和異步并發(fā)的循環(huán)。對(duì)于沒(méi)有計(jì)算機(jī)科學(xué)學(xué)位的人來(lái)說(shuō),想象一下一個(gè)執(zhí)行數(shù)據(jù)庫(kù)查找的 Web 請(qǐng)求。單線程一次只能執(zhí)行一項(xiàng)操作。它不會(huì)等待數(shù)據(jù)庫(kù)響應(yīng),而是繼續(xù)處理隊(duì)列中的其他任務(wù)。在事件循環(huán)中,主循環(huán)展開(kāi)調(diào)用棧,并且不等待回調(diào)。由于循環(huán)不會(huì)阻塞,因此它可以同時(shí)處理多個(gè) Web 請(qǐng)求。多個(gè)請(qǐng)求可以同時(shí)排隊(duì),使其具有并發(fā)性。循環(huán)不會(huì)等待一個(gè)請(qǐng)求的所有操作都完成,而是根據(jù)回調(diào)的出現(xiàn)順序進(jìn)行處理,而不會(huì)阻塞。

循環(huán)本身是半無(wú)限的,這意味著如果調(diào)用?;蚧卣{(diào)隊(duì)列為空,它可以退出循環(huán)??梢詫⒄{(diào)用棧視為同步代碼,例如 console.log,在循環(huán)輪詢更多工作之前展開(kāi)。Node.js 使用底層的 libuv 來(lái)輪詢操作系統(tǒng)以獲取來(lái)自傳入連接的回調(diào)。

您可能想知道,為什么事件循環(huán)在單線程中執(zhí)行?對(duì)于每個(gè)連接所需的數(shù)據(jù)而言,線程在內(nèi)存中相對(duì)較重。線程是操作系統(tǒng)資源,需要啟動(dòng),這無(wú)法擴(kuò)展到數(shù)千個(gè)活動(dòng)連接。

通常情況下,多線程也會(huì)使情況復(fù)雜化。如果回調(diào)返回?cái)?shù)據(jù),它必須將上下文編組回正在執(zhí)行的線程。線程間的上下文切換速度很慢,因?yàn)樗仨毻疆?dāng)前狀態(tài),例如調(diào)用?;蚓植孔兞?。事件循環(huán)在多個(gè)線程共享資源時(shí)可以避免bug,因?yàn)樗鼏尉€程。單線程循環(huán)減少了線程安全邊緣情況,并且可以更快地進(jìn)行上下文切換。這就是循環(huán)背后的真正天才之處。它在保持可擴(kuò)展性的同時(shí)有效地利用了連接和線程。

理論足夠了;現(xiàn)在來(lái)看看代碼是什么樣的。您可以隨意在 REPL 中進(jìn)行操作或下載源代碼。

半無(wú)限循環(huán)

事件循環(huán)必須回答的最大問(wèn)題是循環(huán)是否處于活動(dòng)狀態(tài)。如果是,則確定在回調(diào)隊(duì)列上等待多長(zhǎng)時(shí)間。在每次迭代中,循環(huán)展開(kāi)調(diào)用棧,然后進(jìn)行輪詢。

這是一個(gè)阻塞主循環(huán)的示例:

setTimeout(
  () => console.log('Hi from the callback queue'),
  5000); // 保持循環(huán)活動(dòng)這么長(zhǎng)時(shí)間

const stopTime = Date.now() + 2000;
while (Date.now() < stopTime) {}

如果您運(yùn)行此代碼,請(qǐng)注意循環(huán)被阻塞了兩秒鐘。但是,循環(huán)會(huì)保持活動(dòng)狀態(tài),直到回調(diào)在五秒鐘后執(zhí)行。一旦主循環(huán)解除阻塞,輪詢機(jī)制就會(huì)確定它在回調(diào)上等待多長(zhǎng)時(shí)間。當(dāng)調(diào)用棧展開(kāi)并且沒(méi)有剩余回調(diào)時(shí),此循環(huán)結(jié)束。

回調(diào)隊(duì)列

現(xiàn)在,當(dāng)我阻塞主循環(huán)然后調(diào)度回調(diào)時(shí)會(huì)發(fā)生什么?一旦循環(huán)被阻塞,它就不會(huì)將更多回調(diào)添加到隊(duì)列中:

const stopTime = Date.now() + 2000;
while (Date.now() < stopTime) {}
// 這需要 7 秒才能執(zhí)行
setTimeout(() => console.log('Ran callback A'), 5000);

這次循環(huán)保持活動(dòng)狀態(tài)七秒鐘。事件循環(huán)在其簡(jiǎn)單性方面是愚蠢的。它無(wú)法知道將來(lái)可能會(huì)排隊(duì)什么。在實(shí)際系統(tǒng)中,傳入的回調(diào)會(huì)排隊(duì)并在主循環(huán)可以進(jìn)行輪詢時(shí)執(zhí)行。事件循環(huán)在解除阻塞時(shí)會(huì)順序地經(jīng)歷幾個(gè)階段。因此,為了在關(guān)于循環(huán)的面試中脫穎而出,請(qǐng)避免使用“事件發(fā)射器”或“反應(yīng)器模式”等花哨的術(shù)語(yǔ)。它是一個(gè)簡(jiǎn)單的單線程循環(huán),并發(fā)且非阻塞。

使用 async/await 的事件循環(huán)

為了避免阻塞主循環(huán),一個(gè)想法是用 async/await 包裝同步 I/O:

const fs = require('fs');
const readFileSync = async (path) => await fs.readFileSync(path);

readFileSync('readme.md').then((data) => console.log(data));
console.log('The event loop continues without blocking...');

await 之后出現(xiàn)的任何內(nèi)容都來(lái)自回調(diào)隊(duì)列。代碼看起來(lái)像同步阻塞代碼,但它不會(huì)阻塞。請(qǐng)注意,async/await 使 readFileSync 成為可 then 的,這將其從主循環(huán)中移除。可以將 await 之后出現(xiàn)的任何內(nèi)容視為通過(guò)回調(diào)進(jìn)行的非阻塞操作。

完全披露:以上代碼僅用于演示目的。在實(shí)際代碼中,我建議使用 fs.readFile,它會(huì)觸發(fā)一個(gè)可以圍繞 Promise 包裝的回調(diào)。總體意圖仍然有效,因?yàn)檫@將阻塞 I/O 從主循環(huán)中移除。

更進(jìn)一步

如果我告訴你事件循環(huán)不僅僅是調(diào)用棧和回調(diào)隊(duì)列呢?如果事件循環(huán)不僅僅是一個(gè)循環(huán),而是多個(gè)循環(huán)呢?如果它可以在底層擁有多個(gè)線程呢?

現(xiàn)在,我想帶你深入 Node.js 內(nèi)部。

事件循環(huán)階段

這些是事件循環(huán)階段:

The Node.js Event Loop: A Developer's Guide to Concepts & Code

圖片源:libuv 文檔

  1. 更新時(shí)間戳。事件循環(huán)在循環(huán)開(kāi)始時(shí)緩存當(dāng)前時(shí)間,以避免頻繁進(jìn)行與時(shí)間相關(guān)的系統(tǒng)調(diào)用。這些系統(tǒng)調(diào)用是 libuv 的內(nèi)部調(diào)用。
  2. 循環(huán)是否處于活動(dòng)狀態(tài)?如果循環(huán)具有活動(dòng)句柄、活動(dòng)請(qǐng)求或正在關(guān)閉的句柄,則它處于活動(dòng)狀態(tài)。如所示,隊(duì)列中的待處理回調(diào)使循環(huán)保持活動(dòng)狀態(tài)。
  3. 執(zhí)行到期的定時(shí)器。這是 setTimeout 或 setInterval 回調(diào)運(yùn)行的地方。循環(huán)檢查緩存的now 以使到期的活動(dòng)回調(diào)執(zhí)行。
  4. 執(zhí)行隊(duì)列中的待處理回調(diào)。如果之前的迭代延遲了任何回調(diào),則這些回調(diào)會(huì)在此時(shí)運(yùn)行。輪詢通常會(huì)立即運(yùn)行 I/O 回調(diào),但也有例外。此步驟處理來(lái)自上一次迭代的任何滯后回調(diào)。
  5. 執(zhí)行空閑處理程序——主要是因?yàn)槊划?dāng),因?yàn)檫@些處理程序在每次迭代中都會(huì)運(yùn)行,并且是 libuv 的內(nèi)部處理程序。
  6. 準(zhǔn)備在循環(huán)迭代中執(zhí)行 setImmediate 回調(diào)的句柄。這些句柄在循環(huán)阻塞 I/O 之前運(yùn)行,并為這種回調(diào)類型準(zhǔn)備隊(duì)列。
  7. 計(jì)算輪詢超時(shí)。循環(huán)必須知道它阻塞 I/O 的時(shí)間。這就是它如何計(jì)算超時(shí)的:
    • 如果循環(huán)即將退出,則超時(shí)為 0。
    • 如果沒(méi)有活動(dòng)句柄或請(qǐng)求,則超時(shí)為 0。
    • 如果有任何空閑句柄,則超時(shí)為 0。
    • 如果隊(duì)列中有任何待處理的句柄,則超時(shí)為 0。
    • 如果有任何正在關(guān)閉的句柄,則超時(shí)為 0。
    • 如果以上都不是,則超時(shí)設(shè)置為最接近的定時(shí)器,如果沒(méi)有任何活動(dòng)定時(shí)器,則為無(wú)限
  8. 循環(huán)使用上一個(gè)階段的持續(xù)時(shí)間阻塞 I/O。隊(duì)列中的與 I/O 相關(guān)的回調(diào)在此處執(zhí)行。
  9. 執(zhí)行檢查句柄回調(diào)。此階段是 setImmediate 運(yùn)行的階段,它是準(zhǔn)備句柄的對(duì)應(yīng)階段。在 I/O 回調(diào)執(zhí)行過(guò)程中排隊(duì)的任何 setImmediate 回調(diào)都會(huì)在此處運(yùn)行。
  10. 執(zhí)行關(guān)閉回調(diào)。這些是從已關(guān)閉連接中釋放的活動(dòng)句柄。
  11. 迭代結(jié)束。

您可能想知道為什么輪詢?cè)趹?yīng)該是非阻塞的情況下會(huì)阻塞 I/O?只有當(dāng)隊(duì)列中沒(méi)有待處理的回調(diào)并且調(diào)用棧為空時(shí),循環(huán)才會(huì)阻塞。在 Node.js 中,最接近的定時(shí)器可以通過(guò) setTimeout 設(shè)置,例如。如果設(shè)置為無(wú)限大,則循環(huán)將等待傳入連接以進(jìn)行更多工作。這是一個(gè)半無(wú)限循環(huán),因?yàn)楫?dāng)沒(méi)有剩余工作并且存在活動(dòng)連接時(shí),輪詢會(huì)使循環(huán)保持活動(dòng)狀態(tài)。

以下是此超時(shí)計(jì)算的 Unix 版本,以其全部 C 代碼形式:

setTimeout(
  () => console.log('Hi from the callback queue'),
  5000); // 保持循環(huán)活動(dòng)這么長(zhǎng)時(shí)間

const stopTime = Date.now() + 2000;
while (Date.now() < stopTime) {}

您可能不太熟悉 C 語(yǔ)言,但這讀起來(lái)像英語(yǔ),并且完全按照第七階段所述執(zhí)行。

逐階段演示

為了用純 JavaScript 顯示每個(gè)階段:

const stopTime = Date.now() + 2000;
while (Date.now() < stopTime) {}
// 這需要 7 秒才能執(zhí)行
setTimeout(() => console.log('Ran callback A'), 5000);

因?yàn)槲募?I/O 回調(diào)在階段四和階段九之前運(yùn)行,所以預(yù)計(jì) setImmediate() 會(huì)先觸發(fā):

const fs = require('fs');
const readFileSync = async (path) => await fs.readFileSync(path);

readFileSync('readme.md').then((data) => console.log(data));
console.log('The event loop continues without blocking...');

沒(méi)有 DNS 查詢的網(wǎng)絡(luò) I/O 比文件 I/O 成本更低,因?yàn)樗谥魇录h(huán)中執(zhí)行。文件 I/O 通過(guò)線程池排隊(duì)。DNS 查詢也使用線程池,因此這使得網(wǎng)絡(luò) I/O 與文件 I/O 一樣昂貴。

線程池

Node.js 內(nèi)部有兩個(gè)主要部分:V8 JavaScript 引擎和 libuv。文件 I/O、DNS 查詢和網(wǎng)絡(luò) I/O 通過(guò) libuv 進(jìn)行。

這是整體架構(gòu):

The Node.js Event Loop: A Developer's Guide to Concepts & Code

圖片源:libuv 文檔

對(duì)于網(wǎng)絡(luò) I/O,事件循環(huán)在主線程內(nèi)進(jìn)行輪詢。此線程不是線程安全的,因?yàn)樗粫?huì)與另一個(gè)線程進(jìn)行上下文切換。文件 I/O 和 DNS 查詢是特定于平臺(tái)的,因此方法是在線程池中運(yùn)行它們。一個(gè)想法是自己進(jìn)行 DNS 查詢以避免進(jìn)入線程池,如上面的代碼所示。例如,輸入 IP 地址而不是 localhost 會(huì)將查找從池中移除。線程池中可用的線程數(shù)量有限,可以通過(guò) UV_THREADPOOL_SIZE 環(huán)境變量進(jìn)行設(shè)置。默認(rèn)線程池大小約為四個(gè)。

V8 在單獨(dú)的循環(huán)中執(zhí)行,清空調(diào)用棧,然后將控制權(quán)返回給事件循環(huán)。V8 可以使用多個(gè)線程進(jìn)行其自身循環(huán)之外的垃圾回收。可以將 V8 視為一個(gè)引擎,它接收原始 JavaScript 并將其在硬件上運(yùn)行。

對(duì)于普通程序員來(lái)說(shuō),JavaScript 保持單線程,因?yàn)闆](méi)有線程安全問(wèn)題。V8 和 libuv 內(nèi)部會(huì)啟動(dòng)它們自己?jiǎn)为?dú)的線程以滿足它們自己的需求。

如果 Node.js 中存在吞吐量問(wèn)題,請(qǐng)從主事件循環(huán)開(kāi)始。檢查應(yīng)用程序完成單個(gè)迭代需要多長(zhǎng)時(shí)間。它不應(yīng)超過(guò)一百毫秒。然后,檢查線程池饑餓以及可以從池中驅(qū)逐的內(nèi)容。也可以通過(guò)環(huán)境變量增加池的大小。最后一步是在同步執(zhí)行的 V8 中對(duì) JavaScript 代碼進(jìn)行微基準(zhǔn)測(cè)試。

總結(jié)

事件循環(huán)繼續(xù)迭代每個(gè)階段,因?yàn)榛卣{(diào)被排隊(duì)。但是,在每個(gè)階段內(nèi),都有方法可以排隊(duì)另一種類型的回調(diào)。

process.nextTick() 與 setImmediate()

在每個(gè)階段結(jié)束時(shí),循環(huán)執(zhí)行 process.nextTick() 回調(diào)。請(qǐng)注意,此回調(diào)類型不是事件循環(huán)的一部分,因?yàn)樗诿總€(gè)階段結(jié)束時(shí)運(yùn)行。setImmediate() 回調(diào)是整個(gè)事件循環(huán)的一部分,因此它并不像名稱暗示的那樣立即執(zhí)行。由于 process.nextTick() 需要了解事件循環(huán)的內(nèi)部機(jī)制,因此我通常建議使用 setImmediate()。

您可能需要 process.nextTick() 的幾個(gè)原因:

  1. 允許網(wǎng)絡(luò) I/O 在循環(huán)繼續(xù)之前處理錯(cuò)誤、清理或重試請(qǐng)求。
  2. 可能需要在調(diào)用棧展開(kāi)后但在循環(huán)繼續(xù)之前運(yùn)行回調(diào)。

例如,事件發(fā)射器希望在其自身構(gòu)造函數(shù)中觸發(fā)事件。調(diào)用棧必須先展開(kāi)才能調(diào)用事件。

setTimeout(
  () => console.log('Hi from the callback queue'),
  5000); // 保持循環(huán)活動(dòng)這么長(zhǎng)時(shí)間

const stopTime = Date.now() + 2000;
while (Date.now() < stopTime) {}

允許調(diào)用棧展開(kāi)可以防止諸如 RangeError: Maximum call stack size exceeded 之類的錯(cuò)誤。一個(gè)需要注意的是確保 process.nextTick() 不會(huì)阻塞事件循環(huán)。在同一階段內(nèi)遞歸回調(diào)調(diào)用可能會(huì)導(dǎo)致阻塞問(wèn)題。

結(jié)論

事件循環(huán)在其終極復(fù)雜性中體現(xiàn)了簡(jiǎn)單性。它解決了一個(gè)難題,例如異步性、線程安全性和并發(fā)性。它刪除了無(wú)用或不需要的部分,并以最有效的方式最大限度地提高了吞吐量。因此,Node.js 程序員可以減少追逐異步錯(cuò)誤的時(shí)間,而將更多時(shí)間用于交付新功能。

關(guān)于 Node.js 事件循環(huán)的常見(jiàn)問(wèn)題

什么是 Node.js 事件循環(huán)?Node.js 事件循環(huán)是允許 Node.js 執(zhí)行非阻塞異步操作的核心機(jī)制。它負(fù)責(zé)在單線程事件驅(qū)動(dòng)環(huán)境中處理 I/O 操作、定時(shí)器和回調(diào)。

Node 事件循環(huán)是如何工作的?事件循環(huán)不斷檢查事件隊(duì)列中是否有待處理的事件或回調(diào),并按添加順序執(zhí)行它們。它在一個(gè)循環(huán)中運(yùn)行,根據(jù)事件的可用性處理事件,這使得 Node.js 中的異步編程成為可能。

事件循環(huán)在 Node.js 應(yīng)用程序中的作用是什么?事件循環(huán)是 Node.js 的核心,它確保應(yīng)用程序保持響應(yīng)能力,并且可以處理許多同時(shí)連接,而無(wú)需多線程。

Node.js 事件循環(huán)的階段有哪些?Node.js 中的事件循環(huán)有幾個(gè)階段,包括定時(shí)器、待處理回調(diào)、空閑、輪詢、檢查和關(guān)閉。這些階段決定了事件的處理方式和順序。

事件循環(huán)處理的最常見(jiàn)事件類型有哪些?常見(jiàn)的事件包括 I/O 操作(例如,從文件讀取或發(fā)出網(wǎng)絡(luò)請(qǐng)求)、定時(shí)器(例如,setTimeout 和 setInterval)和回調(diào)函數(shù)(例如,來(lái)自異步操作的回調(diào))。

Node 如何在事件循環(huán)中處理長(zhǎng)時(shí)間運(yùn)行的操作?長(zhǎng)時(shí)間運(yùn)行的 CPU 密集型操作可能會(huì)阻塞事件循環(huán),應(yīng)使用 child_process 或 worker_threads 模塊等模塊將其卸載到子進(jìn)程或工作線程中。

調(diào)用棧和事件循環(huán)有什么區(qū)別?調(diào)用棧是一個(gè)數(shù)據(jù)結(jié)構(gòu),用于跟蹤當(dāng)前執(zhí)行上下文中的函數(shù)調(diào)用,而事件循環(huán)負(fù)責(zé)管理異步和非阻塞操作。它們協(xié)同工作,因?yàn)槭录h(huán)調(diào)度回調(diào)和 I/O 操作的執(zhí)行,然后將它們推送到調(diào)用棧中。

事件循環(huán)中的“tick”是什么?“tick”指的是事件循環(huán)的單個(gè)迭代。在每次 tick 中,事件循環(huán)都會(huì)檢查是否有待處理的事件,并執(zhí)行任何準(zhǔn)備運(yùn)行的回調(diào)。Ticks 是 Node.js 應(yīng)用程序中的基本工作單元。

以上是Node.js事件循環(huán):開(kāi)發(fā)人員的概念和代碼指南的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

Java vs. JavaScript:清除混亂 Java vs. JavaScript:清除混亂 Jun 20, 2025 am 12:27 AM

Java和JavaScript是不同的編程語(yǔ)言,各自適用于不同的應(yīng)用場(chǎng)景。Java用于大型企業(yè)和移動(dòng)應(yīng)用開(kāi)發(fā),而JavaScript主要用于網(wǎng)頁(yè)開(kāi)發(fā)。

JavaScript評(píng)論:簡(jiǎn)短說(shuō)明 JavaScript評(píng)論:簡(jiǎn)短說(shuō)明 Jun 19, 2025 am 12:40 AM

JavascriptconcommentsenceenceEncorenceEnterential gransimenting,reading and guidingCodeeXecution.1)單inecommentsareusedforquickexplanations.2)多l(xiāng)inecommentsexplaincomplexlogicorprovideDocumentation.3)

如何在JS中與日期和時(shí)間合作? 如何在JS中與日期和時(shí)間合作? Jul 01, 2025 am 01:27 AM

JavaScript中的日期和時(shí)間處理需注意以下幾點(diǎn):1.創(chuàng)建Date對(duì)象有多種方式,推薦使用ISO格式字符串以保證兼容性;2.獲取和設(shè)置時(shí)間信息可用get和set方法,注意月份從0開(kāi)始;3.手動(dòng)格式化日期需拼接字符串,也可使用第三方庫(kù);4.處理時(shí)區(qū)問(wèn)題建議使用支持時(shí)區(qū)的庫(kù),如Luxon。掌握這些要點(diǎn)能有效避免常見(jiàn)錯(cuò)誤。

為什么要將標(biāo)簽放在的底部? 為什么要將標(biāo)簽放在的底部? Jul 02, 2025 am 01:22 AM

PlacingtagsatthebottomofablogpostorwebpageservespracticalpurposesforSEO,userexperience,anddesign.1.IthelpswithSEObyallowingsearchenginestoaccesskeyword-relevanttagswithoutclutteringthemaincontent.2.Itimprovesuserexperiencebykeepingthefocusonthearticl

JavaScript與Java:開(kāi)發(fā)人員的全面比較 JavaScript與Java:開(kāi)發(fā)人員的全面比較 Jun 20, 2025 am 12:21 AM

JavaScriptIspreferredforredforwebdevelverment,而Javaisbetterforlarge-ScalebackendsystystemsandSandAndRoidApps.1)JavascriptexcelcelsincreatingInteractiveWebexperienceswebexperienceswithitswithitsdynamicnnamicnnamicnnamicnnamicnemicnemicnemicnemicnemicnemicnemicnemicnddommanipulation.2)

什么是在DOM中冒泡和捕獲的事件? 什么是在DOM中冒泡和捕獲的事件? Jul 02, 2025 am 01:19 AM

事件捕獲和冒泡是DOM中事件傳播的兩個(gè)階段,捕獲是從頂層向下到目標(biāo)元素,冒泡是從目標(biāo)元素向上傳播到頂層。1.事件捕獲通過(guò)addEventListener的useCapture參數(shù)設(shè)為true實(shí)現(xiàn);2.事件冒泡是默認(rèn)行為,useCapture設(shè)為false或省略;3.可使用event.stopPropagation()阻止事件傳播;4.冒泡支持事件委托,提高動(dòng)態(tài)內(nèi)容處理效率;5.捕獲可用于提前攔截事件,如日志記錄或錯(cuò)誤處理。了解這兩個(gè)階段有助于精確控制JavaScript響應(yīng)用戶操作的時(shí)機(jī)和方式。

JavaScript:探索用于高效編碼的數(shù)據(jù)類型 JavaScript:探索用于高效編碼的數(shù)據(jù)類型 Jun 20, 2025 am 12:46 AM

javascripthassevenfundaMentalDatatypes:數(shù)字,弦,布爾值,未定義,null,object和symbol.1)numberSeadUble-eaduble-ecisionFormat,forwidevaluerangesbutbecautious.2)

如何減少JavaScript應(yīng)用程序的有效載荷大?。? />
								</a>
								<a href=如何減少JavaScript應(yīng)用程序的有效載荷大??? Jun 26, 2025 am 12:54 AM

如果JavaScript應(yīng)用加載慢、性能差,問(wèn)題往往出在payload太大,解決方法包括:1.使用代碼拆分(CodeSplitting),通過(guò)React.lazy()或構(gòu)建工具將大bundle拆分為多個(gè)小文件,按需加載以減少首次下載量;2.移除未使用的代碼(TreeShaking),利用ES6模塊機(jī)制清除“死代碼”,確保引入的庫(kù)支持該特性;3.壓縮和合并資源文件,啟用Gzip/Brotli和Terser壓縮JS,合理合并文件并優(yōu)化靜態(tài)資源;4.替換重型依賴,選用輕量級(jí)庫(kù)如day.js、fetch

See all articles