詳解 JS 中的事件迴圈、巨集/微任務、Primise對象、定時器函數,以及其在工作中的應用和註意事項

来源:https://www.cnblogs.com/fx67ll/p/18224944/js-event-loop-job
-Advertisement-
Play Games

為什麼會突然想到寫這麼一個大雜燴的博文呢,必須要從筆者幾年前的一次面試說起。當時的我年輕氣盛,在簡歷上放了自己的博客地址,而面試官應該是翻了我的博客,好幾道面試題都是圍繞著我的博文來提問。其中一個問題,直接使得空氣靜止了五分鐘,也是自從那次面試,我告訴自己,工作實戰中總結的經驗,一定要知其然知其所以... ...


為什麼會突然想到寫這麼一個大雜燴的博文呢,必須要從筆者幾年前的一次面試說起

當時的我年輕氣盛,在簡歷上放了自己的博客地址,而面試官應該是翻了我的博客,好幾道面試題都是圍繞著我的博文來提問

其中一個問題,直接使得空氣靜止了五分鐘,然後面試官結束了這次面試,那就是:如何手寫一個簡易的Promise對象?

在這裡,我也先挖個坑,給你們五分鐘思考並自己回答一下這個問題~ (答案隱藏在文章中自行查看~)

也是自從那次面試,我告訴自己,工作實戰中總結的經驗,一定要知其然知其所以然,才可以真正用好這些核心知識點,不積跬步,無以至千里

說了這麼多的廢話,我們進入今天的博文正題~

目錄

什麼是事件迴圈(Event Loop)

事件迴圈是JavaScript運行時環境的核心機制,用於協調事件、用戶交互、腳本、渲染、網路等。
由於JavaScript是單線程的,事件迴圈使得它能夠執行非阻塞操作,即使在處理IO等長時間運行的任務時也能保持響應性。

事件迴圈的執行順序

在JavaScript的執行模型中,事件迴圈按照以下順序處理任務:

  1. 執行全局腳本代碼,這些同步代碼直接運行。
  2. 當執行棧為空時,事件迴圈會查看微任務隊列。如果隊列中有微任務,就一直執行微任務直到隊列清空。
  3. 執行一個巨集任務(如由 setTimeout()setInterval() 設置的回調)。
  4. 巨集任務執行完畢後,再次執行所有微任務。
  5. 如果有必要,進行UI渲染。
  6. 開始下一輪事件迴圈,處理下一個巨集任務。

通過這種機制,JavaScript可以在單線程中有效地處理非同步事件,同時保持代碼執行的順序和預期效果。
理解這些概念將幫助你更好地設計和調試JavaScript中的非同步代碼。

什麼是巨集任務(MacroTasks)和 微任務(MicroTasks)

巨集任務

巨集任務是 JavaScript 事件迴圈中的一個較大的任務單元,每個巨集任務在執行時會開啟一個新的事件迴圈
一個巨集任務的完成通常會涉及到一個較為完整的工作流程,例如整個腳本的執行、事件(如用戶交互事件)、定時器事件(setTimeout、setInterval)以及瀏覽器的 UI 渲染等
每個巨集任務在執行完畢後,會從任務隊列中清除

常見巨集任務

  • setTimeout():用於設置定時器,在指定的時間間隔後執行任務
  • setInterval():用於設置定時器,在指定的時間間隔迴圈執行任務
  • setImmediate():類似setTimeout(fn, 0) (僅在Node.js中)
  • IO操作:例如文件讀寫、網路請求等
  • UI渲染:瀏覽器需要重新渲染頁面時觸發的任務
  • requestAnimationFrame:動畫渲染函數

拓展提問:點擊和鍵盤事件是巨集任務嗎?

在 JavaScript 中,事件(如點擊和鍵盤事件) 通常被處理為任務
但它們不是巨集任務(macro-tasks)也不是微任務(micro-tasks),而是作為任務隊列中的任務來處理
這些任務在巨集任務和微任務之外,有自己的特殊隊列,通常稱為 任務隊列(task queue)

事件(如點擊和鍵盤事件) 通常被放入任務隊列,並且它們被視為任務的一種。當
事件迴圈執行時,它會首先檢查巨集任務隊列,執行完當前巨集任務後,再執行所有的微任務。
在微任務執行完畢後,瀏覽器可能會進行渲染操作(如果需要),然後事件迴圈會繼續到下一個巨集任務。

因此,可以說點擊和鍵盤事件是作為任務處理的,而不特定分類為巨集任務或微任務。
這種機制確保了 JavaScript 可以在單線程環境中高效地處理非同步事件和操作,同時保持代碼執行的順序性和可預測性。

微任務

微任務是在當前巨集任務執行完畢後立即執行的任務,事件迴圈會在每個巨集任務之後執行所有隊列中的微任務
它們的執行時機是在下一個巨集任務開始之前,當前巨集任務的後續階段,微任務的執行時間早於巨集任務
微任務通常用於處理非同步操作的結果,確保儘可能快地響應

常見微任務

  • Promise.then/catch/finally
  • Promise回調:當Promise狀態改變時,會執行相應的回調函數
  • async/await:使用async函數和await關鍵字進行非同步操作時,await後面的代碼會作為微任務執行
  • process.nextTick:在 Node.js 的事件迴圈的當前階段完成後、下一個事件迴圈階段開始之前,安排一個回調函數儘快執行 (僅在Node.js中)
  • MutaionObserver():瀏覽器中用於觀察DOM樹的變化,監聽DOM變化,當DOM發生變化時觸發微任務

巨集任務和微任務的區別

任務特征

  1. 巨集任務 有明確的非同步任務需要執行和回調;需要其他非同步線程支持
  2. 微任務 沒有明確的非同步任務需要執行,只有回調,不需要其他非同步線程支持

存放位置

  1. 巨集任務 中的事件放在callback queue中,由事件觸發線程維護
  2. 微任務 的事件放在微任務隊列中,由js引擎線程維護

執行順序

  1. 事件迴圈的過程中,執行棧在同步代碼執行完成後,優先檢查 微任務 隊列是否有任務需要執行,如果沒有,再去 巨集任務 隊列檢查是否有任務執行,如此往複
  2. 微任務 一般在當前迴圈就會優先執行,而 巨集任務 會等到下一次迴圈
  3. 因此,微任務 一般比 巨集任務 先執行

隊列數量

  1. 微任務 隊列只有一個
  2. 巨集任務 隊列可能有多個

什麼是 Promise 對象

在 JavaScript 中,Promise 對象是非同步編程的一種重要機制,它代表了一個尚未完成但預期將來會完成的操作的最終結果。
Promise 提供了一種處理非同步操作的方法,使得非同步代碼易於編寫和理解。

Promise 的基本概念

Promise 對象有三種狀態:

  1. Pending(等待中):初始狀態,既不是成功,也不是失敗。
  2. Fulfilled(已完成):意味著操作成功完成。
  3. Rejected(已拒絕):意味著操作失敗或出現錯誤。

如何創建 Promise 對象

Promise 對象是通過 new Promise 構造函數創建的,它接收一個執行器函數作為參數。
這個執行器函數本身接受兩個參數:resolvereject,這兩個參數也是函數。
當非同步操作成功時,調用 resolve 函數;當操作失敗時,調用 reject 函數。

const myPromise = new Promise((resolve, reject) => {
    // 非同步操作
    const condition = true;  // 假設這是某種條件判斷
    if (condition) {
        resolve('Operation successful');
    } else {
        reject('Error occurred');
    }
});

如何使用 Promise 對象

一旦 Promise 被解析(resolved)或拒絕(rejected),它就不能更改狀態。
你可以使用 .then() 方法來處理已完成的 Promise,並使用 .catch() 方法來處理被拒絕的 Promise
還有 .finally() 方法,它在 Promise 完成後被調用,無論其結果如何。

myPromise
    .then(result => {
        console.log(result);  // 處理結果
    })
    .catch(error => {
        console.error(error);  // 處理錯誤
    })
    .finally(() => {
        console.log('Operation completed');  // 最終都會執行
    });

Promise 的優勢

  1. 鏈式調用Promise 允許你通過 .then() 方法鏈式調用多個非同步操作,每個操作依次執行。
  2. 錯誤處理:通過 .catch() 方法,可以集中處理多個非同步操作中的錯誤。
  3. 並行處理Promise.all() 方法允許並行執行多個非同步操作,並等待所有操作完成。

Promise 在工作中的應用場景

Promise 在處理如網路請求、文件操作等非同步操作時非常有用,它使得代碼更加清晰,減少了回調地獄(callback hell)的問題。
通過 Promise,開發者可以寫出更加優雅和可維護的非同步代碼。

如何快速入門上手JavaScript中的 Promise

拓展資料 ———— 快速入門上手JavaScript中的Promise

解答文章開頭的問題:如何手寫一個簡易的 Promise 對象?

function SimplePromise(executor) {
  let onResolve, onReject;
  let fulfilled = false;
  let rejected = false;
  let called = false; // 防止resolve和reject被多次調用
  let value;
  let reason;

  // resolve函數
  function resolve(val) {
    if (!called) {
      value = val;
      fulfilled = true;
      called = true;
      if (onResolve) {
        onResolve(val);
      }
    }
  }

  // reject函數
  function reject(err) {
    if (!called) {
      reason = err;
      rejected = true;
      called = true;
      if (onReject) {
        onReject(err);
      }
    }
  }

  // then方法
  this.then = function(callback) {
    onResolve = callback;
    if (fulfilled) {
      onResolve(value);
    }
    return this; // 支持鏈式調用
  };

  // catch方法
  this.catch = function(callback) {
    onReject = callback;
    if (rejected) {
      onReject(reason);
    }
    return this; // 支持鏈式調用
  };

  // 立即執行傳入的executor函數
  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }
}

// 使用示例
let promise = new SimplePromise((resolve, reject) => {
  setTimeout(() => {
    resolve("Success!");
    // reject("Error!"); // 也可以測試reject情況
  }, 1000);
});

promise.then(result => {
  console.log(result); // 輸出 "Success!"
}).catch(error => {
  console.log(error);
});

什麼是定時器函數

JavaScript 中的定時器函數允許你在一定時間後或者以指定的時間間隔重覆執行代碼。
這些功能主要通過兩個全局函數實現:setTimeout()setInterval()
這些函數是非同步的,意味著它們不會阻塞代碼的執行,而是在指定的延時後將任務加入到 JavaScript 的事件隊列中,等待當前執行棧清空後再執行。

setTimeout()

setTimeout() 函數用於在指定的毫秒數後執行一個函數或指定的代碼。
它不會阻止後續代碼的執行,而是在背後計時,一旦時間到達,就將回調函數加入到事件隊列中,等待執行。

語法

let timeoutID = setTimeout(function[, delay, arg1, arg2, ...]);
  • function:要執行的函數。
  • delay:延遲的時間,以毫秒為單位。如果省略,或者為 0,瀏覽器通常會有最小延遲時間(在HTML5標準中定義為4ms)。
  • arg1, arg2, ...:傳遞給函數的額外參數。

使用示例

console.log("Hello");
setTimeout(() => {
  console.log("World!");
}, 1000);

這個例子會先列印 "Hello",然後大約1秒後列印 "World!"

setInterval()

setInterval() 函數用於重覆調用一個函數或執行代碼片段,每隔指定的周期時間(以毫秒為單位)。
它也是非阻塞的,每次間隔時間到達後,就會嘗試執行指定的代碼。

語法

let intervalID = setInterval(function[, delay, arg1, arg2, ...]);
  • function:要定期執行的函數。
  • delay:執行間隔的時間,以毫秒為單位。
  • arg1, arg2, ...:傳遞給函數的額外參數。

使用示例

let counter = 0;
const intervalID = setInterval(() => {
  console.log("Hello World!");
  counter++;
  if (counter === 5) {
    clearInterval(intervalID);
  }
}, 1000);

這個例子會每秒列印 "Hello World!",併在列印5次後停止

clearTimeout() 和 clearInterval()

這兩個函數用於取消由 setTimeout()setInterval() 設置的定時器。

語法

  • clearTimeout(timeoutID):取消由 setTimeout() 設置的定時器。
  • clearInterval(intervalID):取消由 setInterval() 設置的定時器。

定時器函數的使用註意

雖然 setTimeout()setInterval() 提供了方便的定時執行功能,但它們並不保證精確的時間控制。
JavaScript 是單線程的,如果事件隊列中有其他任務在執行,定時器的回調可能會延遲執行。
此外,瀏覽器或者環境可能對這些函數的行為有特定的限制,如在後臺標簽頁或未激活的視窗中降低定時器的精度或延遲執行,以優化性能和電池壽命。

拓展提問:為什麼要銷毀定時器?Vue中如何銷毀定時器?React中如何銷毀定時器?

在JavaScript中,銷毀定時器是一個重要的操作,主要是為了避免不必要的資源占用和潛在的記憶體泄漏。定時器如果不被適當銷毀,可能會導致一些問題,如:

  1. 繼續執行不必要的操作:如果定時器觸發的函數不再需要執行,定時器仍然活躍會導致額外的計算,這可能影響程式性能。
  2. 記憶體泄漏:在某些情況下,定時器的回調函數可能引用了外部變數或者大型數據結構,如果定時器沒有被銷毀,這些引用關係可能導致所涉及的記憶體無法被垃圾回收,從而造成記憶體泄漏。

Vue中銷毀定時器

在Vue中,通常我們會在組件的生命周期鉤子中設置和銷毀定時器。最常見的做法是在mounted鉤子中創建定時器,併在beforeDestroy(Vue 2.x)或beforeUnmount(Vue 3.x)鉤子中銷毀定時器。例如:

export default {
  mounted() {
    this.timer = setInterval(() => {
      console.log('Interval triggered');
    }, 1000);
  },
  beforeDestroy() { // Vue 2.x
    clearInterval(this.timer);
  },
  beforeUnmount() { // Vue 3.x
    clearInterval(this.timer);
  }
}

React中銷毀定時器

在React中,定時器通常在組件的生命周期方法或者鉤子中設置和清除。使用類組件時,你可以在componentDidMount中設置定時器,併在componentWillUnmount中清除。如果使用函數組件和Hooks,可以在useEffect鉤子中處理定時器:

import React, { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    const timer = setInterval(() => {
      console.log('Interval triggered');
    }, 1000);

    // 清理函數
    return () => clearInterval(timer);
  }, []); // 空依賴數組表示這個effect只在組件掛載時運行一次

  return <div>Check the console.</div>;
}

在這個例子中,useEffect鉤子的返回函數負責清除定時器,這個函數會在組件卸載時被調用,從而確保定時器被適當銷毀。
通過這些方法,可以確保在組件或應用的生命周期結束時,相關的定時器也被正確清除,避免潛在的問題。

補充知識點:什麼是 requestAnimationFrame?

requestAnimationFrame 是一個由瀏覽器提供的 API,用於在下一次瀏覽器重繪之前調用特定的函數,以執行動畫或其他視覺更新。
這個函數是專門為動畫和連續的視覺更新設計的,它可以幫助你創建平滑的動畫效果,因為它能保證在瀏覽器進行下一次重繪之前更新動畫幀。

requestAnimationFrame 的特點

  1. 高效性能requestAnimationFrame 會將動畫函數的執行時機安排在瀏覽器的下一次重繪之前,這樣可以保證動畫的更新和瀏覽器的繪製操作同步進行,從而減少畫面撕裂和不必要的計算和渲染,提高性能。
  2. 節能:相比於 setTimeoutsetIntervalrequestAnimationFrame 是更智能的,因為它會在瀏覽器標簽頁不可見時自動暫停,從而減少CPU、GPU和電力的消耗。
  3. 簡單的使用方式requestAnimationFrame 只需要一個回調函數作為參數,瀏覽器會自動計算出最適合的調用時間。

requestAnimationFrame 的使用示例

假設你想要創建一個簡單的動畫,使一個元素在水平方向上移動:

let xPos = 0;

function animate() {
    xPos += 5; // 每幀向右移動5像素
    element.style.transform = `translateX(${xPos}px)`; // 更新元素位置
    if (xPos < 500) { // 如果元素還沒移動到500像素的位置,繼續動畫
        requestAnimationFrame(animate);
    }
}

requestAnimationFrame(animate); // 開始動畫

在這個示例中,animate 函數會被連續調用,每次調用都會將元素向右移動5像素,直到它達到500像素的位置。

requestAnimationFrame 在工作中應用的註意事項

  • requestAnimationFrame 需要在每一幀都重新調用來繼續動畫。
  • 如果動畫或者視覺更新不再需要,應當使用 cancelAnimationFrame 來取消回調函數的執行,避免不必要的性能消耗。
  • 由於 requestAnimationFrame 的調用時間是由瀏覽器決定的,通常它的頻率會與瀏覽器的刷新率相匹配,例如大多數設備上是每秒60次(即60Hz),但這可能會因設備而異。

補充知識點:什麼是 setImmediate?

setImmediate 是一個在 Node.js 環境中使用的函數,用於安排一個回調函數在當前事件迴圈結束後、下一次事件迴圈開始前被立即執行。
這個函數是特定於 Node.js 的,不是 Web 標準的一部分,因此在瀏覽器環境中不可用。

setImmediate 的功能和用途

setImmediate 的主要用途是將一些需要儘快執行但不必阻塞當前正在執行的操作的代碼延遲執行。它與 setTimeoutprocess.nextTick 類似,但行為略有不同:

  • setImmediate 安排的任務會在當前事件迴圈的“check”階段執行。
  • setTimeout(fn, 0) 會在定時器階段執行,通常會有一小段延遲(最小延遲時間,通常是1毫秒,取決於環境)。
  • process.nextTick 會在當前事件迴圈的任何階段結束後立即執行,甚至在進入下一個事件迴圈階段之前。

setImmediate 的使用示例

下麵是一個簡單的 Node.js 示例,演示了 setImmediate 的用法:

console.log('開始執行');
setImmediate(() => {
    console.log('執行 setImmediate 回調');
});
console.log('結束執行');

在這個例子中,輸出將會是:

開始執行
結束執行
執行 setImmediate 回調

這表明 setImmediate 安排的回調確實是在當前事件迴圈的末尾執行的。

setImmediate 在工作中應用的註意事項

  • 非標準 APIsetImmediate 是一個非標準的 API,只在 Node.js 環境中可用。在瀏覽器中,你可能需要使用 setTimeout(fn, 0) 來達到類似的效果,雖然這兩者在行為上有細微的差別。
  • 使用場景:通常用於處理長時間運行的操作後需要快速響應的場景,或者在處理完一些同步任務後需要儘快執行的非同步代碼。

補充知識點:什麼是 process.nextTick?

process.nextTick 是 Node.js 環境中的一個函數,它用於在 Node.js 的事件迴圈的當前階段完成後、下一個事件迴圈階段開始之前,安排一個回調函數儘快執行。
這意味著無論在事件迴圈的哪個階段調用 process.nextTick,提供的回調函數都會在當前操作完成後立即執行,但在任何I/O事件(包括定時器)或者執行其他計劃任務之前執行。

process.nextTick 的功能和用途

process.nextTick 主要用於確保在當前執行棧運行完畢後、在進行任何非同步操作之前立即處理給定的回調。
這對於處理錯誤、清理資源或者在繼續其他事件之前進行其他緊急計算是非常有用的。

setImmediate 的區別

儘管 process.nextTicksetImmediate 都用於安排非同步操作,但它們的執行時間點不同:

  • process.nextTick 回調在同一事件迴圈階段儘可能早地執行,即在任何I/O事件和定時器之前。
  • setImmediate 設計為在當前事件迴圈的所有I/O事件處理完畢後執行,即在下一個事件迴圈迭代的開始。

process.nextTick 的使用示例

下麵是一個 Node.js 示例,展示了 process.nextTick 的使用:

console.log('開始執行');
process.nextTick(() => {
    console.log('執行 process.nextTick 回調');
});
console.log('結束執行');

在這個例子中,輸出將會是:

開始執行
結束執行
執行 process.nextTick 回調

這表明 process.nextTick 安排的回調確實是在當前事件迴圈的末尾、在其他非同步事件之前執行的。

process.nextTick 在工作中應用的註意事項

  • 遞歸調用:如果 process.nextTick 被遞歸調用,或在一個迴圈中大量調用,它可以導致I/O餓死,因為它會在處理任何I/O事件之前不斷地將新的回調加入到隊列中。
  • 用途選擇process.nextTick 非常適合在當前操作完成後立即需要運行的情況,例如在事件或低級邏輯之後立即處理錯誤或進行清理。

框架拓展:Vue 中有用到 process.nextTick 嗎?

Vue.js 中也使用了 process.nextTick,或者更具體地說,它使用了與之類似的非同步延遲功能。
process.nextTick 是 Node.js 的一個特性,但在瀏覽器環境中,Vue 使用的是 nextTick 方法。
這是 Vue 的全局 API,用於在下一個 DOM 更新迴圈結束後執行延遲回調。
在內部,Vue 會嘗試使用原生的 Promise.thenMutationObserver,或者 setImmediate,最後退回到 setTimeout(fn, 0)

Vue中 nextTick 的應用

  1. 確保 DOM 更新完成:Vue 的數據綁定和 DOM 更新是非同步的。當你更改數據後,DOM 不會立刻更新。nextTick 允許你在 DOM 更新完成後立即運行回調函數,這對於 DOM 依賴的操作非常有用。
  2. 解決狀態更新問題:有時候,你可能在同一方法中多次更改數據,使用 nextTick 可以確保所有的 DOM 更新都完成後再執行某些操作。

Vue中 nextTick 的使用示例

new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  methods: {
    updateMessage() {
      this.message = 'Updated message';
      this.$nextTick(() => {
        // 這個回調將在 DOM 更新後執行
		// `$nextTick()` 用來確保 `console.log('DOM updated')` 的執行發生在 DOM 真正更新之後
        console.log('DOM updated');
      });
    }
  }
});

補充知識點:什麼是 MutationObserver?

MutationObserver 是一個強大的 Web API,用於監視 DOM(文檔對象模型)的變化。
當 DOM 元素被添加、刪除或修改時,MutationObserver 可以被用來非同步地通知這些變化,使開發者能夠響應這些變化並執行相應的操作。

MutationObserver 的功能

MutationObserver 主要用於監視以下類型的 DOM 變化:

  • 子節點的添加或刪除。
  • 屬性的添加、刪除或修改。
  • 文本內容的變更。
  • 更多其他類型的 DOM 變化。

MutationObserver 的用途

這使得 MutationObserver 在開發複雜的 Web 應用時非常有用,特別是在需要響應 DOM 變化來執行某些操作的情況下,如動態內容的載入、用戶界面的自動更新等。

如何使用 MutationObserver

要使用 MutationObserver,你需要創建一個觀察者實例,定義一個回調函數來處理變化,然後指定要監視的 DOM 節點和具體的觀察選項。

MutationObserver 的簡易示例

// 監視目標節點
const targetNode = document.getElementById('some-id');
// 配置觀察選項:
const config = { attributes: true, childList: true, subtree: true };
// 當觀察到變動時執行的回調函數
const callback = function(mutationsList, observer) {
    for(let mutation of mutationsList) {
        if (mutation.type === 'childList') {
            console.log('A child node has been added or removed.');
        } else if (mutation.type === 'attributes') {
            console.log(`The ${mutation.attributeName} attribute was modified.`);
        }
    }
};
// 創建一個觀察者對象並傳入回調函數
const observer = new MutationObserver(callback);
// 開始觀察已配置的變動
observer.observe(targetNode, config);
// 之後,你可以停止觀察
// observer.disconnect();

MutationObserver 在工作中應用的註意事項

  • 性能考慮:雖然 MutationObserver 是非同步的,但過度使用或監視大量的 DOM 變化仍可能影響性能。合理配置觀察選項,只監視必要的變化,可以幫助避免性能問題。
  • 記憶體管理:使用 MutationObserver 時應確保在不需要時斷開觀察(使用 disconnect 方法),以避免記憶體泄漏。

面試問題合集

恭喜你耐心看完本文了,對照下方的問題列表,自我提問一下吧~

什麼是 事件迴圈?
事件迴圈 的執行順序是什麼?
什麼是 巨集任務和微任務?
巨集任務和微任務 有什麼區別?
點擊和鍵盤事件 是巨集任務嗎?
什麼是 Promise 對象?
如何手寫一個簡易的 Promise 對象?
為什麼 PromisesetTimeout 快?
Promise.allPromise.race 有什麼區別?
什麼是 requestAnimationFrame?
什麼是 setImmediate?
什麼是 process.nextTick?
Vue 中有用到 process.nextTick 嗎?
什麼是 MutationObserver?
Vue中如何銷毀定時器?React中如何銷毀定時器?為什麼要銷毀定時器?

我是 fx67ll.com,如果您發現本文有什麼錯誤,歡迎在評論區討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點一顆Star,Thanks~

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 初探富文本之基於虛擬滾動的大型文檔性能優化方案 虛擬滾動是一種優化長列表性能的技術,其通過按需渲染列表項來提高瀏覽器運行效率。具體來說,虛擬滾動只渲染用戶瀏覽器視口部分的文檔數據,而不是整個文檔結構,其核心實現根據可見區域高度和容器的滾動位置計算出需要渲染的列表項,同時不渲染額外的視圖內容。虛擬滾動 ...
  • title: Vue.js 動態組件與非同步組件 date: 2024/6/2 下午9:08:50 updated: 2024/6/2 下午9:08:50 categories: 前端開發 tags: Vue概覽 動態組件 非同步載入 性能提升 路由管理 狀態控制 工具生態 第1章 Vue.js 簡介 ...
  • 從零學習Vue.js 目錄 引言 準備工作 Vue.js 基礎 3.1 Vue 實例 3.2 模板語法 3.3 數據綁定 3.4 計算屬性和偵聽器 3.5 Class 與 Style 綁定 3.6 條件渲染 3.7 列表渲染 3.8 事件處理 3.9 表單輸入綁定 Vue.js 組件 4.1 組件基 ...
  • title: Vue插槽與作用域插槽 date: 2024/6/1 下午9:07:52 updated: 2024/6/1 下午9:07:52 categories: 前端開發 tags: VueSlot ScopeSlot 組件通信 Vue2/3插槽 作用域API 動態插槽 插槽優化 第1章:插槽 ...
  • 一、背景 在日常佈局中,無論是兩欄佈局還是三欄佈局,使用的頻率都非常高 兩欄佈局 兩欄佈局實現效果就是將頁面分割成左右寬度不等的兩列,寬度較小的列設置為固定寬度,剩餘寬度由另一列撐滿, 比如 Ant Design 文檔,藍色區域為主要內容佈局容器,側邊欄為次要內容佈局容器 這裡稱寬度較小的列父元素為 ...
  • XML Web服務是基於WSDL、SOAP、RDF和RSS等標準的網路應用程式組件技術。WSDL描述服務介面和消息格式,SOAP用於結構化信息交換,RDF描述網路資源,RSS則用於發佈網站更新。Web服務特點是自包含、自描述,基於開放協議,可重用且能連接現有軟體。WSDL文檔包含`types`、`m... ...
  • title: vue3組件通信與props date: 2024/5/31 下午9:00:57 updated: 2024/5/31 下午9:00:57 categories: 前端開發 tags: Vue3組件 Props詳解 生命周期 數據通信 模板語法 Composition API 單向數據 ...
  • 一、是什麼 單例模式(Singleton Pattern):創建型模式,提供了一種創建對象的最佳方式,這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建 在應用程式運行期間,單例模式只會在全局作用域下創建一次實例對象,讓所有需要調用的地方都共用這一單例對象,如下圖所示: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...