詳解 JS 中的事件循環、宏/微任務、Primise對象、定時器函數,以及其在工作中的應用和注意事項

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

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

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

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

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

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

目錄

  • 事件循環(Event Loop)
    • 事件循環的執行順序
  • 宏任務(MacroTasks)和微任務(MicroTasks)
    • 常見宏任務
    • 常見微任務
    • 宏任務和微任務的區別
  • Promise 對象
    • Promise 的基本概念
    • 如何創建 Promise 對象
    • 如何使用 Promise 對象
    • Promise 的優勢
    • Promise 在工作中的應用場景
    • 如何快速入門上手 JavaScript 中的 Promise
    • 手寫一個簡易的 Promise 對象
  • 定時器函數
    • setTimeout()
    • setInterval()
    • clearTimeout() 和 clearInterval()
    • 定時器函數的使用注意
    • 銷毀定時器
      • 為什么要銷毀定時器?
      • Vue 中如何銷毀定時器?
      • React 中如何銷毀定時器?
  • 補充知識點
    • requestAnimationFrame
    • setImmediate
    • process.nextTick
      • Vue中有用到 process.nextTick 嗎?
    • MutationObserver
  • 面試問題合集

什么是事件循環(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.xclearInterval(this.timer);},beforeUnmount() { // Vue 3.xclearInterval(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~ 😃
轉發請注明參考文章地址,非常感謝!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20409.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20409.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20409.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AWS與SAP擴大戰略合作:通過AI增強ERP解決方案

西雅圖和沃爾多夫——亞馬遜網絡服務&#xff08;AWS&#xff09;與SAP SE宣布擴大戰略合作&#xff0c;旨在革新現代云企業資源規劃&#xff08;ERP&#xff09;體驗&#xff0c;并幫助企業通過生成式人工智能&#xff08;AI&#xff09;提升功能和效率。 AWS和SAP共同努力&a…

【Linux】將U盤中的程序更新到開發板中 shell 腳本

1. 代碼 攪拌名稱&#xff1a; refresh.sh #!/bin/sh#from _fromDir$1#to _toDir$2#umount umount /dev/sda1#mount mount /dev/sda1 /media/udisk0#copy cp -r $_fromDir $_toDirif [ $? -eq 0 ] thenchmod 777 $_toDirif [ $? -eq 0 ]thensyncecho "success"el…

Python entry用法:深入剖析與實戰應用

Python entry用法&#xff1a;深入剖析與實戰應用 在Python編程的世界中&#xff0c;entry并非一個內置的關鍵字或方法&#xff0c;但它在某些上下文中&#xff0c;如Tkinter GUI編程中&#xff0c;是一個重要的組件。本文將圍繞entry組件的用法&#xff0c;從四個方面、五個方…

select多個客戶端連接,傳輸數據時只能順序傳輸產生原因

1. 場景描述 即A先連接,B后連接&#xff0c;只能先A后B依次輸入數據&#xff0c;服務端依次讀取數據 這是因為進行循環遍歷lfd之后的描述符時&#xff0c;沒有判斷文件描述符i是否在newset集合中 //cfd發生變化 for(int ilfd1;i<maxfd;i){printf("i num %d\t"…

Matplotlib | 繪制柱狀圖

簡介 安裝 Matplotlib 開始繪制 簡單柱狀圖 改變顏色 改變紋理 改變邊框樣式 改變透明度 改變柱子寬度 改變圖表標題 ?編輯 并列柱狀圖 橫向柱狀圖 堆疊柱狀圖 更多函數 簡介 柱狀圖&#xff08;Bar chart&#xff09;&#xff0c;是一種以長方形的長度為變量的…

黑白群暉激活AME(Advanced Media Extention)

黑群暉激活Advanced Media Extensions&#xff08;AME&#xff09;解碼HEVC視頻和HEIC圖片 聲明&#xff1a;此教程在正版群暉系統中進行的操作&#xff0c;雖然也能用于非正版系統中AME的安裝&#xff0c;但是在非正版系統中安裝AME屬于破解行為&#xff0c;對系統造成的影響和…

2006NOIP普及組真題 1. 明明的隨機數

線上OJ&#xff1a; 【06NOIP普及組】明明的隨機數 核心思想&#xff1a; 本題的要求是 1、去重 2、排序 以上兩個要求正好可以使用 set 來實現。set 自帶了去重和排序的功能。輸出時使用 iterator 即可。 解法一、set #include <bits/stdc.h> using namespace std;in…

這里一定有你不知道的VS調試技巧

目錄 使用環境&#xff1a;Visual Studio 2022,如無特殊說明&#xff0c;都是在Debug、x64環境下編譯 一.什么是BUG 二.調試快捷鍵 F9&#xff1a;創建斷電或取消斷點 條件斷點&#xff1a;滿足這個條件才觸發 F5&#xff1a;啟動調試&#xff0c;經常?來直接跳到下?個斷…

20 - grace數據處理 - 地下水儲量計算過程分解 - 地下水儲量計算

20 - grace數據處理 - 地下水儲量計算過程分解 - 地下水儲量計算 0 引言1 地下水儲量變化計算過程0 引言 由水平衡方程可以將地下水儲量的計算過程分解為3個部分,第一部分計算陸地水儲量變化、第二部分計算地表水儲量變化、第三部分計算冰后回彈改正、第四部分計算地下水儲量變…

python爬蟲之JS逆向——網頁數據解析

目錄 一、正則 1 正則基礎 元字符 基本使用 通配符: . 字符集: [] 重復 位置 管道符和括號 轉義符 轉義功能 轉義元字符 2 正則進階 元字符組合(常用) 模式修正符 re模塊的方法 有名分組 compile編譯 二、bs4 1 四種對象 2 導航文檔樹 嵌套選擇 子節點、…

Vue:Bin Code Editor格式化JSON編輯器

最終效果如下圖所示&#xff0c; Bin Code Editor安裝 npm或yarn安裝命令如下&#xff0c; npm i bin-code-editor -S # or yarn add bin-code-editor 組件注冊 全局注冊 在 main.js 中寫入導入以下內容&#xff0c; import Vue from vue; import CodeEditor from bin-cod…

服務器數據恢復—異常斷電導致ESXi虛擬機無法啟動的數據恢復案例

服務器數據恢復環境&#xff1a; 某大廠PS4000服務器&#xff0c;服務器上部署VMware ESXi虛擬化平臺。 服務器故障&#xff1a; 機房斷電&#xff0c;重啟后服務器中的某臺虛擬機不能正常啟動。管理員查看虛擬機配置文件&#xff0c;發現無法啟動的虛擬機的配置文件除了磁盤文…

【每日刷題】Day53

【每日刷題】Day53 &#x1f955;個人主頁&#xff1a;開敲&#x1f349; &#x1f525;所屬專欄&#xff1a;每日刷題&#x1f34d; &#x1f33c;文章目錄&#x1f33c; 1. 1019. 鏈表中的下一個更大節點 - 力扣&#xff08;LeetCode&#xff09; 2. 116. 填充每個節點的下一…

Exce 兩列一組對齊呈現,缺失補 0

Excel 里有 多 組數據&#xff0c;每組 2 列&#xff0c;每組長度不同。第 1 列是編號&#xff0c;列之間的編號有重復。 ABCDEFGH1Mass10Mass11Mass12Mass132802200581309088146532802225938133306824779282975598142002482273148413154988335698822331305832720485110460842…

計算機考研|408 值得選擇嗎?有哪些優勢?

408當然非常值得報考&#xff0c;但是現在的408已經卷麻了&#xff01; 現在越來越多的學校改考408&#xff0c;光今年就有6所發布通知&#xff0c;宣布改考408&#xff0c;分別是&#xff1a; 這對考408的學生肯定是好消息&#xff0c;后面可能還會有學校陸續改考&#xff0c;…

一、實現一個簡單的 Google Chrome 擴展程序

目錄 &#x1f9ed; 效果展示 # 圖示效果 a. 拓展程序列表圖示效果&#xff1a; b. 當前選項卡頁面右鍵效果&#xff1a; c. 拓展程序消息提示效果&#xff1a; &#x1f4c7; 項目目錄結構 # 說明 # 結構 # 文件一覽 ? 核心代碼 # manifest.json # background.j…

SLAM ORB-SLAM2(26)重定位過程

SLAM ORB-SLAM2(26)重定位過程 1. 前言2. 詞袋模型2.1. 加快搜索2.2. 在文本檢索的應用2.3. 引入視覺圖像分類3. 重定位總體過程3.1. 計算當前幀特征點的詞袋向量3.2. 根據用詞袋查找相似的候選關鍵幀3.3. 通過詞袋模型進行初步匹配3.4. 查詢較匹配的關鍵幀3.4.1. 通過PnP投影…

華為 2024 屆實習校園招聘-硬件通?/單板開發——第五套

華為 2024 屆實習校園招聘-硬件通?/單板開發——第五套 部分題目分享&#xff0c;完整版帶答案(有答案和解析&#xff0c;答案非官方&#xff0c;未仔細校正&#xff0c;僅供參考&#xff09;&#xff08;共十套&#xff0c;每套四十題選擇題&#xff09;獲取&#xff08;WX:…

java期末細節知識整理(一)

1.java程序的執行過程&#xff1a;先編譯后解釋。也就是我們在idea寫的文件叫做java源文件&#xff08;.java結尾的文件&#xff09;&#xff0c;經過編譯器會生成字節碼文件&#xff08;.class結尾的文件&#xff09;&#xff0c;再通過解釋器進行實現 2.棧用來存儲引用類型的…

易語言本地IP一鍵切換程序(附帶源碼)

易語言本地IP一鍵切換程序 效果圖部分源碼源碼領取下期更新預報 效果圖 部分源碼 .判斷開始 (單選框1.選中 &#xff1d; 真)標簽5.標題 &#xff1d; #換行符 &#xff0b; “正在切換IP.”.如果真 (運行 (“netsh interface ip set address ” &#xff0b; #引號 &#xff…