一、Node.js 事件循環
Node.js 的事件循環(Event Loop)是其異步編程的核心機制,它使得 Node.js 可以在單線程中實現非阻塞 I/O 操作。
🔁 簡要原理
Node.js 是基于 libuv 實現的,它使用事件循環來處理非阻塞操作。事件循環的主要作用是:
“不斷檢查任務隊列(如回調、I/O、定時器),并按階段執行回調。”
📊 事件循環的幾個階段
-
timers:執行
setTimeout
和setInterval
的回調。 -
pending callbacks:執行 I/O 操作失敗的回調(如錯誤處理)。
-
idle, prepare:內部使用。
-
poll:等待新的 I/O 事件,如文件讀寫。
-
check:執行
setImmediate()
的回調。 -
close callbacks:如
socket.on('close', ...)
。
🧪 示例代碼:事件循環的順序
setTimeout(() => {console.log('setTimeout');
}, 0);setImmediate(() => {console.log('setImmediate');
});Promise.resolve().then(() => {console.log('Promise');
});process.nextTick(() => {console.log('nextTick');
});
🧾 輸出順序可能是:
nextTick
Promise
setTimeout
setImmediate
? 原因:
-
process.nextTick()
和Promise.then()
是微任務(microtask),優先執行。 -
setTimeout
和setImmediate
是宏任務(macrotask),排在后面。
📘 應用場景
-
高并發服務器(如 HTTP 服務器)
-
異步數據庫訪問
-
異步文件 I/O 操作
-
消息隊列處理
🎯 總結
特性 | 描述 |
---|---|
單線程 | Node.js 本身是單線程的 |
非阻塞 I/O | 借助事件循環與回調實現并發處理 |
微任務優先 | nextTick > Promise > setTimeout |
一、瀏覽器事件循環和 Node.js 的區別
瀏覽器和 Node.js 都使用事件循環(Event Loop)來處理異步任務,但由于運行環境不同,它們的事件循環機制在架構設計、宏任務與微任務處理、任務來源和模塊支持等方面存在明顯差異。
🌐 一、瀏覽器事件循環機制
瀏覽器的事件循環遵循 HTML5 標準,基本結構如下:
1. 執行順序
-
同步任務(調用棧)
-
微任務隊列(Microtasks):如
Promise.then
、MutationObserver
-
宏任務隊列(Macrotasks):如
setTimeout
、setInterval
、requestAnimationFrame
2. 典型任務來源
任務類型 | 示例 |
---|---|
宏任務 | setTimeout 、setInterval 、message 、UI 渲染 、XHR onload |
微任務 | Promise.then 、queueMicrotask 、MutationObserver |
3. 特點
-
每執行一個宏任務,立即清空所有微任務。
-
瀏覽器事件循環中含有 UI 渲染階段,微任務清空后才允許渲染。
?? 二、Node.js 的事件循環機制
Node.js 基于 libuv 庫實現自己的事件循環,主要包含 6 個階段,不完全等同于瀏覽器模型。
1. Node.js 事件循環階段
-
timers:處理
setTimeout
、setInterval
-
pending callbacks:處理某些 I/O 的回調
-
idle, prepare:僅內部使用
-
poll:檢索 I/O 事件
-
check:處理
setImmediate
-
close callbacks:處理
close
事件,如socket.on('close')
每個階段之間都會執行微任務隊列。
2. 微任務來源
-
process.nextTick()
(優先級最高,不屬于微任務隊列,是獨立隊列) -
Promise.then()
(真正的微任務)
3. 特點
-
process.nextTick
比Promise.then
更早執行。 -
沒有 UI 渲染階段(非瀏覽器)。
-
setImmediate
與setTimeout(..., 0)
行為不同。
🔍 三、主要區別對比
項目 | 瀏覽器 | Node.js |
---|---|---|
環境 | 有 UI 渲染 | 無 UI 渲染 |
宏任務示例 | setTimeout , setInterval | setTimeout , setImmediate |
微任務隊列 | Promise , MutationObserver | Promise , process.nextTick (優先) |
微任務執行時機 | 每個宏任務后執行所有微任務 | 每個階段后執行所有微任務(先執行 nextTick ) |
特殊隊列 | 無 nextTick | process.nextTick 隊列優先于微任務 |
底層實現 | 瀏覽器廠商自研 | libuv 實現多平臺 I/O |
? 總結記憶口訣
瀏覽器關注 UI,先宏后微;Node 有 Tick,分階段處理。
二、Node.js異步編程
下面是關于 Node.js 中異步編程的兩種主要方式 —— Promise
和 async/await
的示例與解釋:
一、Promise 示例與解釋
function fetchData() {return new Promise((resolve, reject) => {setTimeout(() => {const success = true;if (success) {resolve("數據加載成功");} else {reject("數據加載失敗");}}, 1000);});
}fetchData().then(data => {console.log(data); // 輸出:數據加載成功}).catch(error => {console.error(error);});
? 說明:
-
Promise
表示一個異步操作的最終完成(或失敗)及其結果值。 -
.then()
處理成功,.catch()
處理錯誤。 -
適合鏈式調用多個異步任務。
二、async/await 示例與解釋
function fetchData() {return new Promise((resolve) => {setTimeout(() => {resolve("數據加載成功");}, 1000);});
}async function getData() {try {const result = await fetchData();console.log(result); // 輸出:數據加載成功} catch (error) {console.error(error);}
}getData();
? 說明:
-
async
表示函數內部可能存在異步操作。 -
await
表示等待 Promise 處理完成,簡化回調地獄。 -
語法更接近同步邏輯,可讀性好,推薦使用。
如需講解 回調函數 → Promise → async/await
的演進過程或應用在實際項目場景里,我也可以繼續補充。
三、libuv 工作機制
libuv
是 Node.js 底層的核心庫之一,負責 跨平臺的異步 I/O 操作。理解 libuv
的工作機制,有助于深入掌握 Node.js 的高性能和事件驅動模型。
? libuv 是什么?
libuv
是一個用 C 編寫的跨平臺異步 I/O 庫,為 Node.js 提供以下能力:
-
事件循環(Event Loop)
-
異步文件系統操作
-
網絡通信(TCP、UDP)
-
子進程管理
-
定時器(Timers)
-
DNS 查詢
-
線程池
🔄 libuv 的工作機制(核心組成)
1. Event Loop 事件循環
libuv 實現了事件循環的機制,管理所有異步任務的執行時機。
2. 任務隊列分階段處理
libuv 的事件循環大致如下(簡化版本):
while (循環運行中) {處理 timers 階段(如 setTimeout、setInterval)處理 I/O callbacks(異步操作的回調)處理 idle, prepare 回調處理 poll 階段(處理新的 I/O 事件)處理 check 階段(setImmediate)處理 close callbacks(如 socket關閉)執行 microtask(如 Promise.then) → V8 控制
}
3. 線程池(Thread Pool)
對于 CPU 密集型或無法異步的操作(如 fs.readFile
),libuv 使用線程池異步執行:
-
默認線程數:4
-
可以通過
UV_THREADPOOL_SIZE
環境變量配置
📌 舉例說明(libuv 在線程池中運行 I/O):
const fs = require('fs');fs.readFile('example.txt', 'utf8', (err, data) => {console.log('文件內容:', data);
});
此處 readFile
實際由 libuv 在線程池中執行,不阻塞主線程,執行完回調被加入事件循環隊列。
📊 總結圖示(流程簡化)
JS 調用異步API(如 fs.readFile)↓
libuv 將其交由線程池處理↓
任務完成后,結果回調加入 Event Loop 的隊列↓
Event Loop 執行回調函數
如果你需要一張完整的圖示來可視化這個執行流程,我可以畫圖說明(更詳細展示與 V8、線程池、事件循環的協作)。是否需要?
四、Cluster 實現多進程
1. 概念
Node.js 是單線程運行的,但它的底層 libuv 使用線程池處理異步 I/O。單線程模型對 I/O 密集型應用非常高效,但在 CPU 密集型任務或者需要利用多核 CPU 的場景下,單線程的限制就明顯了。
Cluster 模塊允許你創建多個 Node.js 進程(worker),這些進程共享同一個服務器端口,從而實現多核 CPU 的并行利用。每個 worker 進程是 Node.js 的一個單獨實例,擁有自己的事件循環。
這樣,Cluster 能讓你充分利用多核 CPU,提升 Node.js 應用的性能和吞吐量。
2. 代碼示例
下面是一個使用 Cluster 的簡單示例,創建多個 worker,監聽同一個端口:
const cluster = require('cluster');
const http = require('http');
const os = require('os');if (cluster.isMaster) {// 獲取CPU核心數const cpuCount = os.cpus().length;console.log(`主進程 ${process.pid} 正在運行`);console.log(`啟動 ${cpuCount} 個 worker`);// Fork 子進程for (let i = 0; i < cpuCount; i++) {cluster.fork();}// 監聽 worker 退出事件cluster.on('exit', (worker, code, signal) => {console.log(`worker ${worker.process.pid} 已退出,啟動新的 worker`);cluster.fork();});
} else {// Worker 進程運行 HTTP 服務器http.createServer((req, res) => {res.writeHead(200);res.end(`由進程 ${process.pid} 處理請求\n`);}).listen(8000);console.log(`worker ${process.pid} 啟動`);
}
3. 講解
-
cluster.isMaster
判斷當前進程是不是主進程。 -
主進程會根據 CPU 核數 fork 出對應數量的 worker 進程。
-
每個 worker 進程都執行同樣的代碼,但
cluster.isMaster
為 false,啟動一個 HTTP 服務器監聽同一端口。 -
Node.js Cluster 模塊內部會將進入的請求分發給不同的 worker,負載均衡處理。
-
當某個 worker 進程退出時,主進程捕獲
exit
事件,自動重啟一個新的 worker,保證服務穩定。 -
每個 worker 進程擁有自己的進程 ID (
process.pid
),方便區分請求是由哪個進程處理。
4. 總結
-
Cluster 允許 Node.js 程序多進程運行,充分利用多核 CPU。
-
主進程負責管理 worker 進程的生命周期。
-
Worker 進程獨立運行同樣的服務器代碼,監聽同一個端口。
-
請求會被均衡分發到不同的 worker,提高并發處理能力。
-
適合 CPU 密集型或高并發的 Node.js 服務。
如果需要,我還可以幫你寫更完整的示例,或者介紹更高級的用法,比如 IPC 通信,歡迎告訴我!
五、V8 引擎原理
1. 概念
V8 引擎是 Google 開發的開源 JavaScript 引擎,主要用于 Chrome 瀏覽器和 Node.js 環境。它負責將 JavaScript 代碼編譯、優化并執行,極大提升了 JavaScript 的運行效率。
V8 的核心特點包括:
-
即時編譯(JIT):將 JavaScript 代碼即時編譯成機器碼,而非先解釋執行,提高性能。
-
隱藏類(Hidden Classes)和內聯緩存(Inline Caches):優化對象屬性訪問,減少動態查找的開銷。
-
垃圾回收(Garbage Collection):自動管理內存,回收不再使用的對象。
-
多階段編譯:先快速生成初步代碼,再逐漸優化熱代碼。
2. V8 執行流程簡述
-
解析階段:V8 把 JavaScript 源代碼解析成抽象語法樹(AST)。
-
編譯階段:使用 Ignition 解釋器將 AST 轉換成字節碼(intermediate representation)。
-
執行階段:解釋字節碼運行程序,同時收集熱點代碼信息。
-
優化階段:HotSpot 優化編譯器將熱點字節碼編譯為高效的機器碼。
-
垃圾回收:定期回收無用對象釋放內存。
3. 代碼示例
V8 是底層引擎,運行時隱藏在 Node.js 或 Chrome 里。下面是一個用 Node.js 運行 JavaScript 的簡單示例,展示 V8 執行 JavaScript:
// demo.js
function fibonacci(n) {if (n <= 1) return n;return fibonacci(n - 1) + fibonacci(n - 2);
}console.log(fibonacci(10));
執行:
node demo.js
背后 V8 會:
-
將這個函數編譯成字節碼。
-
解釋執行,識別熱點函數(遞歸調用頻繁)。
-
對該函數進行優化編譯,生成高效機器碼。
-
最終輸出結果。
4. 講解
-
V8不是簡單的解釋器,它通過多階段編譯和優化,極大提升 JS 代碼性能。
-
傳統的 JS 解釋器逐行執行代碼,而 V8 首先把代碼編譯成字節碼,運行更快。
-
在運行過程中,V8 會分析哪些代碼“熱”(被頻繁執行),并通過優化編譯器將其轉換成原生機器碼,提高執行速度。
-
隱藏類和內聯緩存是 V8 優化對象訪問的關鍵技術,類似于為 JS 對象動態生成“類”,快速定位屬性。
-
V8 使用分代垃圾回收,比如新生代和老生代,來高效管理內存,減少停頓時間。
如果你想,我還能幫你梳理 V8 的內存分配、垃圾回收機制,或者介紹 Node.js 如何通過 V8 實現高性能,隨時告訴我!
六、V8 引擎內存分配與垃圾回收機制
1. 概念
V8 引擎內存分配
V8 引擎在執行 JavaScript 代碼時,需要在內存中為對象、函數、變量等分配空間。它將內存劃分為不同的區域,主要包括:
-
新生代(Young Generation):存放新創建的對象,分配速度快,采用 Scavenge 算法進行垃圾回收。
-
老生代(Old Generation):存放經過多次垃圾回收仍存活的長生命周期對象,采用標記-清除(Mark-Sweep)和標記-整理(Mark-Compact)算法回收。
-
代碼區(Code Space):存放編譯后的機器碼。
-
大對象空間(Large Object Space):存放特別大的對象,避免影響新生代和老生代的內存管理。
垃圾回收機制
V8 使用自動垃圾回收,自動管理內存,釋放不再被引用的對象。其核心算法包括:
-
Scavenge(新生代回收):采用復制算法,將存活對象從一塊內存區復制到另一塊,快速清理內存。
-
標記-清除(Mark-Sweep):標記所有存活對象,清除未標記對象。
-
標記-整理(Mark-Compact):類似標記-清除,但會整理存活對象,避免內存碎片。
垃圾回收器根據對象的生命周期自動將其從新生代晉升到老生代,提高回收效率。
2. 代碼示例
V8 的內存分配和垃圾回收是引擎內部行為,普通 JavaScript 代碼無法直接控制,但可以通過編寫大量對象生成與銷毀來觀察其效果。
示例:大量創建對象模擬內存使用
function createObjects() {let arr = [];for (let i = 0; i < 1000000; i++) {arr.push({ index: i, time: Date.now() });}return arr;
}let objects = createObjects();// 模擬釋放內存
setTimeout(() => {objects = null; // 解除引用,等待垃圾回收console.log('Objects dereferenced, eligible for GC');
}, 5000);
運行這段代碼時,V8 會為 arr
分配大量內存。當 objects = null
后,數組及其包含的對象失去引用,V8 垃圾回收器會在合適時間回收這部分內存。
3. 講解
-
新生代和老生代的設計是基于**大部分對象“朝生暮死”**的經驗:新創建的對象大多數生命周期短暫,快速回收;存活較久的對象才進入老生代。
-
Scavenge 復制算法效率高,適合快速回收新生代內存,避免內存碎片。
-
老生代垃圾回收用 標記-清除和標記-整理算法,后者減少碎片,保證大塊內存連續,方便長壽命對象管理。
-
代碼區內存存放編譯后的機器碼,方便函數和代碼快速執行。
-
大對象空間獨立分配,避免影響普通對象的內存回收策略。
-
JavaScript 代碼中不能直接手動觸發垃圾回收,但通過釋放對象引用(如賦值
null
),讓垃圾回收器能回收無用內存。 -
V8 的垃圾回收是并發和增量式,盡量減少程序停頓,提高響應性能。
如果你想深入了解 V8 垃圾回收的算法細節、如何通過 --trace_gc
等命令行參數查看垃圾回收日志,我也可以幫你寫具體說明!
七、V8 引擎定位性能瓶頸
1. 概念
V8 引擎在執行 JavaScript 代碼時,通過多種機制定位和優化性能瓶頸,以提升代碼執行效率。主要包括:
-
內置性能分析工具:V8 支持采樣 CPU 和內存使用情況,幫助開發者找出代碼熱點(hot spots)。
-
優化編譯器(TurboFan):通過收集運行時信息,動態編譯熱點代碼成機器碼,提高性能。
-
內聯緩存(Inline Cache):加速屬性訪問,減少查找時間。
-
性能剖析(Profiler):V8 可以生成性能分析數據,用于發現執行瓶頸。
通過這些手段,V8 能自動發現“慢代碼”,并對其進行重點優化。
2. 代碼示例
JavaScript 代碼本身不直接控制 V8 的性能分析,但可以利用 Node.js 提供的性能工具,比如 --prof
選項開啟 V8 性能分析。
示例:使用 Node.js 運行腳本并生成性能日志
node --prof demo.js
假設 demo.js
內容:
function slowFunction() {let sum = 0;for (let i = 0; i < 1e7; i++) {sum += i;}return sum;
}console.log(slowFunction());
運行后,會生成 isolate-0x...-v8.log
文件,使用 node --prof-process
解析:
node --prof-process isolate-0x...-v8.log > processed.txt
processed.txt
會包含函數執行時間、調用次數等性能數據,幫助定位性能瓶頸。
3. 講解
-
V8 的性能優化基于采樣分析,它不記錄所有細節,而是定時采樣調用棧,減少性能開銷。
-
通過
--prof
,V8 記錄運行時的函數調用和時間分布,開發者可以找出耗時多的函數。 -
V8 識別“熱點代碼”,使用 TurboFan 優化編譯器將其轉為高效機器碼。
-
內聯緩存減少了屬性訪問的動態查找,是提升代碼訪問性能的關鍵。
-
在 Node.js 或 Chrome 開發者工具中,也能結合 V8 采集的性能數據,直觀查看代碼瓶頸。
-
通過定位性能瓶頸,開發者可以優化算法、減少不必要的循環、避免低效操作,從而提升整體性能。
如果你需要,我可以幫你寫更詳細的性能分析步驟,或者示范如何結合 Chrome DevTools 使用 V8 Profiler。
八、Web3.js使用手冊在哪里看
1. 概念
Web3.js 的官方使用手冊(文檔)是學習和掌握該庫的最佳途徑。它詳細介紹了 Web3.js 的安裝、API 結構、常用功能、示例代碼和進階用法,幫助開發者快速上手與以太坊區塊鏈交互。
2. 官方文檔地址
Web3.js 官方文檔網址:
-
web3.js - Ethereum JavaScript API — web3.js 1.0.0 documentation
這里你可以找到:
-
安裝和快速開始教程
-
主要模塊和類的 API 說明(如
web3.eth
、web3.utils
) -
示例代碼和使用指南
-
常見問題和社區鏈接
3. 如何查閱使用手冊
-
首頁快速入門
先瀏覽 “Getting Started” 或 “Quick Start” 部分,了解如何安裝 Web3.js 以及基本連接。 -
模塊導航
文檔頁面左側有目錄,按模塊分類,比如:-
web3.eth
:以太坊核心 API,如賬戶、交易、合約等。 -
web3.utils
:工具函數,如單位轉換、哈希計算。 -
web3.shh
:點對點消息。 -
web3.net
:網絡相關接口。
-
-
查找具體 API
搜索你想用的功能,比如 “getBalance”、“sendTransaction”,查看參數、返回值和示例。 -
示例代碼
結合文檔里的示例代碼,實際寫代碼測試,幫助理解。 -
版本對應
注意文檔版本對應你使用的 Web3.js 版本,避免接口不兼容。
4. 額外資源
-
GitHub 主頁:https://github.com/ChainSafe/web3.js
-
官方示例:https://github.com/ChainSafe/web3.js/tree/1.x/examples
-
社區論壇和問答(如 Stack Overflow)
八、Web3.js與以太坊等區塊鏈交互
1. 概念
Web3.js 是一個 JavaScript 庫,用于與以太坊區塊鏈進行交互。它封裝了以太坊的 JSON-RPC 接口,使開發者能夠輕松調用智能合約、發送交易、查詢賬戶余額等操作。
通過 Web3.js,前端或后端應用可以:
-
連接以太坊節點(如 Infura、Alchemy 或本地節點)
-
讀取鏈上數據(賬戶信息、合約狀態)
-
發送交易(轉賬、調用合約方法)
-
監聽鏈上事件
2. 代碼示例
以下是一個使用 Web3.js 連接以太坊節點、查詢賬戶余額的示例:
const Web3 = require('web3');// 連接到以太坊節點(這里用Infura的主網節點)
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID');async function getBalance(address) {try {const balanceWei = await web3.eth.getBalance(address);const balanceEth = web3.utils.fromWei(balanceWei, 'ether');console.log(`賬戶 ${address} 余額: ${balanceEth} ETH`);} catch (err) {console.error('查詢余額出錯:', err);}
}const address = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'; // 示例地址
getBalance(address);
3. 智能合約交互示例
假設你有一個已部署的智能合約地址和ABI,調用合約的只讀方法:
const contractABI = [ /* 合約ABI數組 */ ];
const contractAddress = '0xYourContractAddressHere';const contract = new web3.eth.Contract(contractABI, contractAddress);async function callContractMethod() {try {const result = await contract.methods.yourMethodName().call();console.log('調用結果:', result);} catch (err) {console.error('調用合約方法失敗:', err);}
}callContractMethod();
4. 講解
-
連接節點:Web3.js 需要連接一個以太坊節點,可以是遠程公共節點(Infura、Alchemy)或者本地節點。
-
賬戶余額查詢:通過
web3.eth.getBalance
查詢某地址的以太幣余額,返回單位為 Wei(以太坊最小單位),通常用web3.utils.fromWei
轉換成人類易讀的 Ether。 -
智能合約交互:通過合約的 ABI 和地址實例化
web3.eth.Contract
,調用methods
中定義的函數。-
.call()
用于只讀調用,不消耗 Gas,不產生交易。 -
.send()
用于狀態更改調用,需要簽名并消耗 Gas。
-
-
交易發送:通過
web3.eth.sendTransaction
或contract.methods.methodName().send()
發送交易,通常需要私鑰或錢包簽名。 -
事件監聽:Web3.js 支持監聽智能合約事件,方便前端實時響應鏈上變化。
如果你想,我還可以幫你寫完整的發送交易示例、錢包集成示例,或者講解 Web3.js 的更多高級用法。
九、Ethers.js 在哪里看使用手冊,是干嘛的
1. 概念
Ethers.js 的使用手冊(官方文檔)是學習和掌握這個庫的核心資源,提供詳細的 API 說明、安裝指南、示例代碼和進階用法。它幫助開發者理解如何用 Ethers.js 與以太坊區塊鏈交互,比如連接節點、查詢余額、調用合約、發送交易等。
2. 官方文檔地址
Ethers.js 官方文檔網址是:
-
https://docs.ethers.io/
這是 Ethers.js 官方維護的文檔,內容覆蓋:
-
快速開始
-
核心模塊(Provider、Wallet、Contract 等)
-
API 詳細說明
-
常用工具函數
-
進階主題(事件監聽、合約工廠、ENS 等)
3. 如何使用手冊
-
首頁快速開始
了解安裝和基礎用法,快速寫出第一個查詢余額或調用合約的代碼。 -
模塊分類導航
根據功能查找對應模塊的使用方法,例如查Provider
如何連接節點,查Wallet
如何管理私鑰。 -
API 參考
查看每個類和方法的參數、返回值和示例,便于正確調用。 -
示例代碼
文檔中大量示例,方便模仿和調試。 -
版本匹配
確保文檔版本和你項目中安裝的 Ethers.js 版本一致。
4. 額外資源
-
GitHub 倉庫:https://github.com/ethers-io/ethers.js
-
社區問答(Stack Overflow)
-
教程視頻和博客
九、Ethers.js 與以太坊等區塊鏈交互
1. 概念
Ethers.js 是一個輕量級的 JavaScript 庫,用于與以太坊區塊鏈交互。它功能類似于 Web3.js,但設計更加模塊化和簡潔,且更注重安全性和易用性。
Ethers.js 支持:
-
連接以太坊節點(本地或遠程,如 Infura)
-
查詢賬戶余額和鏈上數據
-
構造、簽名和發送交易
-
與智能合約進行交互
-
事件監聽和解析
-
錢包管理(私鑰、助記詞)
2. 代碼示例
安裝 Ethers.js
npm install ethers
查詢賬戶余額示例
const { ethers } = require('ethers');// 連接到以太坊主網節點
const provider = new ethers.providers.InfuraProvider('mainnet', 'YOUR_INFURA_PROJECT_ID');async function getBalance(address) {const balance = await provider.getBalance(address);console.log(`賬戶余額: ${ethers.utils.formatEther(balance)} ETH`);
}const address = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e';
getBalance(address);
調用智能合約只讀方法示例
const contractABI = [ /* 合約 ABI 數組 */ ];
const contractAddress = '0xYourContractAddressHere';const contract = new ethers.Contract(contractAddress, contractABI, provider);async function callContractMethod() {try {const result = await contract.yourMethodName();console.log('調用結果:', result);} catch (err) {console.error('調用合約方法失敗:', err);}
}callContractMethod();
3. 講解
-
Provider(提供者):Ethers.js 使用
Provider
對象連接以太坊節點,用于讀取區塊鏈數據(余額、交易、合約狀態)。支持多種類型節點,如 JSON-RPC、Infura、Alchemy 等。 -
Wallet(錢包):管理私鑰和簽名交易,支持從助記詞、私鑰或硬件錢包創建。
-
Contract(合約):實例化合約后,可以調用智能合約中的函數,
call
方法用于只讀調用,send
(需要 Wallet 簽名)用于發送交易。 -
工具函數:Ethers.js 包含很多實用工具,如單位轉換(Wei 和 Ether)、哈希計算、編碼解碼等。
-
Ethers.js API 設計更現代、易用,類型定義完善,適合 TypeScript 開發。
-
它更注重安全性,默認不會暴露用戶私鑰,必須顯式創建 Wallet 進行簽名。
如果需要,我也可以幫你寫發送交易、事件監聽等更復雜的示例,或者給你對比 Web3.js 和 Ethers.js 的優缺點。
十、Web3.js和Ethers.js區別,各自的作用
Web3.js和Ethers.js一般來說只用其中一個庫就夠了,因為 Web3.js 和 Ethers.js 都能完成和以太坊區塊鏈的主要交互功能,比如:
-
查詢余額
-
發送交易
-
調用智能合約
-
監聽事件
它們功能大部分重疊,沒必要同時用兩個,避免增加項目復雜度和包體積。
選哪個合適?
-
想用更輕量、現代、TypeScript 支持好、錢包管理方便,建議選 Ethers.js。
-
需要兼容老項目或已有依賴,或者用的生態比較多是 Web3.js,就用 Web3.js。
如果你只做一個項目,學會用一個庫就足夠高效,沒必要混著用。
1. Web3.js 和 Ethers.js 的區別及作用概述
特性/方面 | Web3.js | Ethers.js |
---|---|---|
定位和設計 | 以太坊官方較早的 JS 庫,功能全面但較龐大 | 輕量級、模塊化設計,更加現代和易用 |
體積大小 | 較大,功能豐富但包體積較重 | 更小,適合前端項目,對資源有限環境友好 |
API 風格 | API 設計相對復雜,有些冗余 | API 更簡潔,鏈式調用方便,類型定義更好(TS 友好) |
錢包支持 | 通常與外部錢包配合使用,錢包管理較弱 | 內置 Wallet 支持,私鑰、助記詞管理方便 |
社區支持與生態 | 更成熟,很多教程和項目使用 | 發展迅速,社區活躍,越來越多項目青睞 |
功能覆蓋 | 功能全面,涵蓋所有鏈交互需求 | 功能齊全但更注重核心,擴展性好 |
文檔和易用性 | 文檔較豐富,但入門門檻稍高 | 文檔結構清晰,示例豐富,更容易上手 |
事件監聽 | 支持事件監聽,使用起來稍復雜 | 事件監聽使用簡潔,支持過濾器 |
性能和穩定性 | 穩定性好,廣泛使用,但有些接口較舊 | 性能優化好,設計現代,支持最新以太坊特性 |
2. 各自作用
Web3.js
-
主要用于和以太坊區塊鏈進行交互,功能涵蓋賬戶管理、交易、智能合約調用、事件監聽等。
-
適合需要全面功能,已有成熟項目或依賴 Web3.js 生態的開發者。
-
常用于 DApp 前端與以太坊節點通信。
Ethers.js
-
設計更輕量且模塊化,強調安全和易用,支持錢包管理(私鑰、助記詞)。
-
適合希望代碼體積小、使用現代 JS/TS 特性、方便錢包集成的項目。
-
也適合后端腳本和服務,提供簡潔且強大的鏈交互能力。
3. 總結建議
-
如果你是新項目,注重代碼質量和易用性,推薦用 Ethers.js。
-
如果需要兼容大量現有教程或項目,或者使用的庫/框架依賴 Web3.js,則用 Web3.js。
需要的話,我可以幫你寫一份兩者的對比示例代碼,或者幫你快速上手其中任意一個。
十一、賬戶管理(Account Management)
功能點:
-
創建賬號
-
從私鑰導入
-
查詢余額
Web3.js 示例:
const Web3 = require('web3');
const web3 = new Web3('https://mainnet.infura.io/v3/你的API_KEY');// 創建新賬戶
const newAccount = web3.eth.accounts.create();
console.log(newAccount);// 從私鑰導入
const account = web3.eth.accounts.privateKeyToAccount('0x你的私鑰');
console.log(account.address);// 查詢余額
web3.eth.getBalance(account.address).then(balance => {console.log('ETH余額:', web3.utils.fromWei(balance, 'ether'));
});
Ethers.js 示例:
import { ethers } from 'ethers';const provider = new ethers.InfuraProvider('mainnet', '你的API_KEY');// 創建錢包
const wallet = ethers.Wallet.createRandom();
console.log(wallet.address);// 導入私鑰
const walletFromPK = new ethers.Wallet('0x你的私鑰', provider);// 查詢余額
provider.getBalance(walletFromPK.address).then(balance => {console.log('ETH余額:', ethers.utils.formatEther(balance));
});
十二、交易構造與簽名(Transaction Creation & Signing)
功能點:
-
構造交易(to、value、gas等)
-
簽名交易
-
廣播交易
Web3.js 示例:
const tx = {to: '0x接收方地址',value: web3.utils.toWei('0.01', 'ether'),gas: 21000,
};web3.eth.accounts.signTransaction(tx, '0x你的私鑰').then(signed => web3.eth.sendSignedTransaction(signed.rawTransaction)).then(receipt => console.log('交易成功:', receipt.transactionHash));
Ethers.js 示例:
const tx = {to: '0x接收方地址',value: ethers.utils.parseEther('0.01'),
};walletFromPK.sendTransaction(tx).then(txResponse => {console.log('發送中:', txResponse.hash);return txResponse.wait();
}).then(receipt => {console.log('交易成功:', receipt.transactionHash);
});
十三、調用智能合約(Call Smart Contract)
功能點:
-
加載合約 ABI 和地址
-
調用讀取函數(call)
-
調用修改函數(send/寫交易)
Web3.js 示例:
const abi = [ /* 合約ABI */ ];
const contractAddress = '0x合約地址';
const contract = new web3.eth.Contract(abi, contractAddress);// 讀取數據(不會上鏈)
contract.methods.name().call().then(console.log);// 寫數據(需要簽名+發交易)
contract.methods.setValue(123).send({ from: account.address, gas: 100000 });
Ethers.js 示例:
const abi = [ /* 合約ABI */ ];
const contractAddress = '0x合約地址';
const contract = new ethers.Contract(contractAddress, abi, walletFromPK);// 讀取
contract.name().then(console.log);// 寫入(需要簽名)
contract.setValue(123).then(tx => tx.wait()).then(console.log);
賬戶管理、交易構造與簽名、調用智能合約——知識總結表
功能 | Web3.js | Ethers.js |
---|---|---|
創建/導入賬戶 | web3.eth.accounts | ethers.Wallet |
查詢余額 | web3.eth.getBalance | provider.getBalance |
構造交易 | 手動構造 + sign/send | wallet.sendTransaction() |
調用合約函數 | contract.methods.fn | contract.fn() |
簽名交易/消息 | signTransaction | wallet.signMessage() |