WEB3全栈开发——面试专业技能点P1Node.js / Web3.js / Ethers.js
一、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 代码无法直接控制,但可以通过编写大量对象生成与销毁来观察其效果。
示例:大量创建对象模拟内存使用
js
复制编辑
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() |
相关文章:

WEB3全栈开发——面试专业技能点P1Node.js / Web3.js / Ethers.js
一、Node.js 事件循环 Node.js 的事件循环(Event Loop)是其异步编程的核心机制,它使得 Node.js 可以在单线程中实现非阻塞 I/O 操作。 🔁 简要原理 Node.js 是基于 libuv 实现的,它使用事件循环来处理非阻塞操作。事件…...

Vscode下Go语言环境配置
前言 本文介绍了vscode下Go语言开发环境的快速配置,为新手小白快速上手Go语言提供帮助。 1.下载官方Vscode 这步比较基础,已经安装好的同学可以直接快进到第二步 官方安装包地址:https://code.visualstudio.com/ 双击一直点击下一步即可,记…...
Java八股文——MySQL篇
文章目录 Java八股文——MySQL篇慢查询如何定位慢查询?如何分析慢SQLExplain标准答案 索引索引类型索引底层数据结构什么是聚簇索引什么是非聚簇索引?(二级索引)(回表)聚集索引选取规则回表查询 什么是覆盖…...
Oracle数据库学习笔记 - 创建、备份和恢复
Oracle数据库学习笔记 创建,备份和恢复 Oracle 版本基于11g 尽量不使用图形界面方式,操作适用于linux和windows 创建数据库 创建实例 # 步骤1:设置环境变量 export ORACLE_SIDmyorcl export ORACLE_HOME/u01/app/oracle/product/19.0.0/dbh…...

Go语言--语法基础5--基本数据类型--输入输出(1)
I : input 输入操作 格式化输入 scanf O : output 输出操作 格式化输出 printf 标准输入 》键盘设备 》 Stdin 标准输出 》显示器终端 》 Stdout 异常输出 》显示器终端 》 Stderr 1 、输入语句 Go 语言的标准输出流在打印到屏幕时有些参数跟别的语言…...

永磁同步电机无速度算法--自适应龙贝格观测器
一、原理介绍 传统龙伯格观测器,在设计观测器反馈增益矩阵K时,为简化分析与设计,根据静止两相坐标系下的对称关系,只引入了K、K,两个常系数,且在实际应用时,大多是通过试凑找到一组合适的反馈增益系数缺乏…...

LangChain工具集成实战:构建智能问答系统完整指南
导读:在人工智能快速发展的今天,如何构建一个既能理解自然语言又能调用外部工具的智能问答系统,成为许多开发者面临的核心挑战。本文将为您提供一套完整的解决方案,从LangChain内置工具包的基础架构到复杂系统的工程实践。 文章深…...

【razor】x264 在 的intra-refresh和IDR插帧
你提到的是这样一个情况: 使用 DirectShow 采集,帧率稳定(如回调了20帧)使用 x264 的 total intra refresh 模式(intra-refresh=1) 进行编码但编码过程中「隔几十秒才有一帧intra(关键帧)」这不正常,具体分析如下: 🎯 一、问题核心 x264 的 intra refresh 模式(特…...
分库分表的取舍
文章目录 大数据量下采用**水平分表**的缺点**1. 跨表查询复杂性与性能下降****2. 数据分布不均衡****3. 分布式事务与一致性问题****4. 扩展性受限****5. 查询条件限制与索引管理复杂****6. 数据迁移与维护成本高****7. 业务逻辑复杂度增加****总结** shardingJdbc分片策略**1…...

随机算法一文深度全解
随机算法一文深度全解 一、随机算法基础1.1 定义与核心特性1.2 算法优势与局限 二、随机算法经典案例2.1 随机化快速排序原理推导问题分析与策略代码实现(Python、Java、C) 2.2 蒙特卡罗方法计算 π 值原理推导问题分析与策略代码实现(Python…...

在 Conda 环境下配置 Jupyter Notebook 环境和工作目录
作为数据科学家或Python开发者,Jupyter Notebook 是我们日常工作的得力工具。本文将详细介绍如何在 Conda 环境中配置 Jupyter Notebook,包括环境设置和工作目录管理,帮助你打造高效的工作流程。 为什么要在 Conda 环境中使用 Jupyter Noteb…...

MS39531N 是一款正弦驱动的三相无感直流电机驱动器,具有最小振动和高效率的特点
MS39531N 是一款正弦驱动的三相无感直流电机驱动器,具有最小振动和高效率的特点 简述 MS39531 是一款正弦驱动的 三相无感直流电机驱动器 ,具有最小振动和高效率的特点。该驱动器内部集成了基本的闭环速度控制功能,能够根据特定的应用定制电…...

web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究
web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究 如何找到Defi中的交易机会 把defi看做是一个完全开放的金融产品图表,可以看到所有的一切东西;我们要沿着这些金融图表找到一些最优的路径,就…...

分析 java 的 Map<String,Map<String, List<Map<String,Integer>>>>
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;public class Test02 {public static void main(String[] args) {//分析方法:由外层向内层逐渐拆解要定义的变量。再由内向外进行变量赋值//外层第一层&#x…...

ChatterBox - 轻巧快速的语音克隆与文本转语音模型,支持情感控制 支持50系显卡 一键整合包下载
ChatterBox 是一个近期备受关注的开源语音克隆与文本转语音(TTS)模型,由 Resemble AI 推出,具备体积轻巧及超快的推理速度等特色。它也是首个支持情感夸张控制的开放源代码 TTS 模型,这一强大功能能让您的声音脱颖而出…...

前端开发面试题总结-HTML篇
文章目录 HTML面试高频问答一、HTML 的 src 和 href 属性有什么区别?二、什么是 HTML 语义化?三、HTML的 script 标签中 defer 和 async 有什么区别?四、HTML5 相比于 HTML有哪些更新?五、HTML行内元素有哪些? 块级元素有哪些? 空(void)元素有哪些?六、iframe有哪些优点…...

嵌入式学习--江协stm32day4
只能说拖延没有什么好结果,欠下的债总是要还的。 ADC 模拟信号转化为数字信号,例如温度传感器将外部温度的变化(模拟信号),转换为内部电压的变化(数字信号) IN是八路输入,下方是选择…...

【Matlab】连接SQL Server 全过程
文章目录 一、下载与安装1.1 SQL Server1.2 SSMS1.3 OLE DB 驱动程序 二、数据库配置2.1 SSMS2.2 SQL Server里面设置2.3 设置防火墙2.4 设置ODBC数据源 三、matlab 链接测试 一、下载与安装 微软的,所以直接去微软官方下载即可。 1.1 SQL Server 下载最免费的Ex…...
MS8551/MS8552/MS8554 单电源、轨到轨输入输出、高精度运放,可替代AD8551/AD8552/AD8554
MS8551/MS8552/MS8554 单电源、轨到轨输入输出、高精度运放,可替代AD8551/AD8552/AD8554 简述 MS8551/8552/8554 是轨到轨输入输出的高精度运算放大器,它有极低的输入失调电压和偏置电流,单电源电压范围为 1.8V 到 5V 。 MS8551/8552/85…...
什么是 Ansible 主机和组变量
Ansible 是一款强大的自动化工具,可简化配置管理、应用程序部署和预配等 IT 任务。其最有价值的功能之一是能够定义变量,从而为不同的主机和组定制剧本。本文将解释 Ansible 中组变量和主机变量的概念,并通过实际示例说明它们的用法。 Ansib…...
F#语言的区块链
F#语言在区块链中的应用 引言 区块链技术在过去十年中迅速崛起,成为了推动金融、供应链、物联网等多个领域创新的重要力量。近年来,随着区块链技术的普及,各种编程语言也纷纷被应用于区块链的开发中。F#语言作为一种功能性编程语言…...

9.RV1126-OPENCV 视频的膨胀和腐蚀
一.膨胀 1.视频流的膨胀流程 之前膨胀都是在图片中进行的,现在要在视频中进行也简单,大概思路就是:获取VI数据,然后把VI数据给Mat化发给VENC模块,然后VENC模块获取,这样就完成了。流程图: 2.代…...
查找 Vue 项目中未使用的依赖
在 Vue 项目中查找未使用的依赖可以通过以下几种方法: 1. 使用 depcheck 工具 depcheck 是一个专门用于查找项目中未使用依赖的工具。 安装: bash npm install -g depcheck使用: bash depcheck它会列出: 未使用的依赖缺失…...

华为OD机考-内存冷热标记-多条件排序
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextInt();int[] arr new int[a];for(int…...
UDP 与 TCP 调用接口的差异:面试高频问题解析与实战总结
在日常开发中,我们经常使用封装良好的 TCP 协议栈,比如 HTTP 客户端、Moudou 网络库等,因此很少从“裸 API”角度深入了解 TCP 和 UDP 的套接字调用流程。但在一些系统底层开发或者网络编程面试中,常被问到“TCP 和 UDP 的调用流程…...

AI时代:学习永不嫌晚,语言多元共存
最近看到两个关于AI的两个问题,“现在开始学习AI,是不是为时已晚?”、“AI出现以后,翻译几乎已到末路,那么,随着时代的进步,中文会一统全球吗?” 联想到自己正在做的“万能AI盒”小程…...
『React』Fragment的用法及简写形式
在 React 渲染组件时,每个组件只能返回一个根节点(root element)。传统上,如果我们需要渲染多条并列的元素,通常会使用一个多余的 <div> 或者其他容器标签将它们包裹起来。但是,这样会在最终的 HTML …...
强化学习入门:交叉熵方法数学推导
前言 最近想开一个关于强化学习专栏,因为DeepSeek-R1很火,但本人对于LLM连门都没入。因此,只是记录一些类似的读书笔记,内容不深,大多数只是一些概念的东西,数学公式也不会太多,还望读者多多指教…...
CSS3 的特性
目录 CSS3 的特性CSS3 的三大特性1. 层叠性2. 继承性3. 优先级 CSS3 新增特性1. 选择器2. 盒模型3. 背景4. 渐变5. 过渡6. 动画7. 2D/3D 变换8. 弹性布局9. 网格布局10. 媒体查询11. 多列布局12. 文字阴影和盒子阴影 CSS3 的特性 CSS3 的三大特性 1. 层叠性 定义:…...
Vue前端篇——Vue 3的watch深度解析
📌 前言 在 Vue.js 的世界中,“数据驱动”是其核心理念之一。而在这一理念下,watch 扮演着一个非常关键的角色。它允许我们监听响应式数据的变化,并在其发生变化时执行特定的业务逻辑。 本文将通过实际代码示例,深入…...