Bun vs Node.js:新一代JavaScript运行时能否取代Node? 1. Bun 到底是何方神圣1.1 一个工具包揽运行时、打包器、包管理器先说个场景你打开 GitHub 刷到一个新项目package.json里写的是packageManager: bun1.1.0你第一反应是不是“这啥玩意儿怎么不用 npm”我一开始也是这么想的直到真的花了一个下午把一个小服务从 Node 迁到 Bun 上跑起来才意识到这东西并不是简单地“快一点”而是整个工具链的设计逻辑都不一样。Bun 是什么一句话它是一个 JavaScript 运行时同时内置了包管理器、打包器、测试运行器、原生 TypeScript 支持甚至自带.env加载和热重载。也就是说你在 Node 里需要 npm nodemon ts-node jest webpack 这一套组合拳才能搭起来的环境在 Bun 里一个二进制文件全干完了。它是由 Jarred Sumner 在 2022 年发起的开源项目底层用了 JavaScriptCore 引擎就是 Safari 那个而不是 Node 用的 V8。我第一次听说“Bun 能取代 Node.js”这个说法的时候心里是打了个问号的。毕竟 Node.js 从 2009 年发布到现在积累了十几年生态全球几百万开发者在上面干活怎么可能说换就换。但当我实际跑了一遍 benchmark再看了它内置的那些设计思路又觉得这种讨论其实非常有价值——因为 Bun 逼着我们去思考一个问题Node 这么多年沉淀下来的东西哪些是真正不可替代的哪些只是“大家都这么用所以懒得改”的历史包袱。1.2 为什么 Bun 敢说“快”——JavaScriptCore 与底层实现很多文章一上来就甩 benchmark 数据说 Bun 冷启动比 Node 快 4 倍、安装依赖快 10 倍但很少有人讲清楚它为什么快。我先说结论快不是靠优化出来的是靠“重新设计”出来的。第一个关键点是引擎。Node.js 用的是 V8 引擎这是 Chrome 的 JavaScript 引擎性能当然很强但 V8 的设计目标是服务于浏览器场景启动时需要做很多初始化和预热工作。Bun 选用 JavaScriptCore这个引擎在苹果生态里被 Safari 用了十几年对“快速启动”这件事有天然优势——你想想看Safari 打开一个网页可不能让用户等两秒白屏。JavaScriptCore 在冷启动时的内存占用和初始化开销明显更小这正是 Bun 冷启动快的底层原因之一。第二个关键点是语言。Bun 本身不是用 C 写的而是用 Zig 写的。Zig 是一门比较新的系统编程语言它的特点是内存管理和底层控制非常精细而且没有 C 那套繁琐的继承和模板机制。用 Zig 写运行时意味着可以在更底层的位置做优化比如直接控制内存布局、减少不必要的系统调用。很多人觉得用 Zig 只是个噱头其实不是它对性能的影响是实打实的。第三个关键点是“内置一切”的设计哲学。Bun 把所有工具都塞进一个二进制里好处是省去了进程间的通信开销。你在 Node 里跑node scripts/build.js然后还要再起一个ts-node或esbuild的进程去处理 TypeScript每多一个进程就有一次 IPC 的损耗。Bun 把所有事情放在同一个进程里做完光这一点就省掉了大量的上下文切换。1.3 Bun 的“全家桶”设计从 install 到 test 不用换工具我实际用了两周之后最直观的感受不是“快”而是“少”。以前我开一个新 Node 项目要经历以下流程装 Node配 nvm 管理版本。初始化 npm纠结用 npm 还是 pnpm 还是 yarn。装 TypeScript配 tsconfig。装 ts-node 或 tsx 用于开发调试。装 nodemon 做热重载。选一个测试框架jest 或者 vitest。配置环境变量加载用 dotenv 或 cross-env。这套流程就算熟练工也得折腾半小时中间还可能撞上版本兼容问题——比如 Node 升级之后某个原生模块编译不过去。而 Bun 这边一个bun init就生成了项目骨架直接支持.ts文件不需要任何编译步骤自带热重载bun --hot自带测试运行器bun test自带.env读取自带打包器。从初始化到写出第一个接口全程不超过五分钟。这种“全家桶”设计让我想到一个类比Node 生态很像自己组装台式机每个配件都能自由选择性能上限高但你需要懂硬件兼容性Bun 更像苹果的一体机给你的每个部件都是经过优化的你不需要关心底层搭配开箱即用。自由和便捷之间没有绝对的对错但如果你不是那种喜欢折腾工具链的开发者Bun 的体验确实会让人上瘾。2. Node.js 的护城河在哪里2.1 生态才是最大的壁垒聊到“Bun 能不能取代 Node.js”绕不开的一个事实就是生态。npm 上现在已经有两百多万个包几乎你能想到的任何一个功能需求都能找到一个已经被大量生产环境验证过的第三方库。Node.js 这些年沉淀下来的不只是代码还有数不清的技术文档、Stack Overflow 回答、博客教程、企业最佳实践。Bun 内置的 API 确实和 Node 兼容了一部分比如fs、path、http这些核心模块但它做不到 100% 兼容。举一个很简单的例子很多老项目会用到process.nextTick和setImmediate的执行顺序差异Bun 虽然也实现了这两个 API但在某些边缘 case 下的行为表现可能和 Node 不一样。再比如 Node 的http模块默认返回的IncomingMessage对象有一堆历史遗留属性Bun 的Bun.serve返回的Request对象是基于 Web Fetch API 的两者结构完全不同。这意味着什么意味着如果你想把一个生产环境的 Node 服务迁移到 Bun大概率不是换个运行时那么简单而是需要改代码。现在很多 npm 包虽然声明支持 Bun但真正跑起来之后才会发现有一些细小的行为差异。我有一个真实的经历项目里用了fastify框架它在 Bun 上能跑但某个用了onSend钩子的插件在 Bun 下的执行顺序和 Node 不一样导致响应头异常。这种问题排查起来非常痛苦因为你的业务代码没问题、框架版本没问题纯粹是运行时的行为差异。2.2 Node 也在进化Builtin、Sea 和性能改进很多人对比 Node 和 Bun 的时候犯了一个错误——把 Node 当成一个静态的、不再发展的东西。实际上 Node.js 的迭代速度并不慢只是它的步子比较稳妥毕竟要照顾生态里几百万个包的兼容性。Node 20 之后发布了几个很值得关注的能力。一个是Builtin模块node:test它让 Node 有了内置的测试运行器虽然功能比 jest 和 vitest 弱一些但对于小项目来说已经够用了。另一个是Single Executable ApplicationsSEA可以把 Node 应用打包成单个可执行文件这直接对标了 Bun 的“单文件分发”能力。还有一个是--experimental-strip-types标志从 Node 22.6 开始可以直接运行不带编译步骤的 TypeScript 文件虽然现在还有一堆限制但方向是明确的。性能方面Node 也在不断优化。V8 引擎本来就是世界上优化最深的 JavaScript 引擎之一加上 Undici 这个 HTTP 客户端的引入Node 在处理网络请求方面的性能已经有了大幅提升。你可能觉得 Bun 的 HTTP 服务比 Node 快两倍很夸张但在真实的生产场景中瓶颈往往不在运行时的裸性能上而在数据库查询、网络延迟、日志写入这些地方。一个跑在 Node 上的服务如果有 50ms 的数据库查询耗时那么换到 Bun 上把运行时耗时从 5ms 压到 2ms对整个请求延迟的改善只有 3ms用户根本感知不到。2.3 “能用”和“好用”是两回事迁移成本到底有多大我在前面说了 Bun 的很多优点但实际操作下来从 Node 迁到 Bun 的真实成本是很多人没有意识到的。我把它分成三层第一层是API 替换成本。Bun 虽然实现了大部分 Node API但像http、https、stream这些核心模块在接口设计上就有差异。如果你用的是 Express 这类框架框架本身帮你屏蔽了底层 API 差异那么迁移成本不高但如果你直接用http.createServer写原生服务那几乎每一行都要改。第二层是原生模块成本。Node 生态里大量依赖node-gyp编译的原生模块比如bcrypt、sharp、sqlite3。这些模块在 Bun 下要么不支持、要么需要重新编译而且因为 Bun 用的是 JavaScriptCore 而不是 V8很多node-gyp模块的编译脚本并没有针对 JSC 做适配。我的建议是如果你要用 Bun优先选择纯 JavaScript 实现的替代库比如用bcryptjs替代bcrypt虽然性能差一些但至少能跑。第三层是团队心智成本。这个最容易被忽略。你的团队成员熟悉 Node 的调试工具Chrome DevTools、Node inspector、熟悉NODE_ENV的约定、熟悉 pm2 的进程管理方式。换到 Bun 之后这些经验全都需要重置。不是说你学不会而是对于一个以交付业务为主的技术团队来说切换运行时带来的短期效率下降是实打实的。这也是为什么很多公司在 Bun 出来两年之后仍然观望——他们不是不知道 Bun 快而是不想为一个“可能更好的未来”去承担现阶段的确定性风险。3. 关键指标横评Bun vs Node.js 到底差多少3.1 冷启动速度开发体验的直观差异冷启动是 Bun 最容易被感知到优势的场景。我实测过在一台 M2 MacBook Pro 上面跑同一个 hello world HTTP 服务# 使用 Node 启动 node server.js # 输出: Server running at http://localhost:3000 # 耗时约 120ms # 使用 Bun 启动 bun server.js # 输出: Server running at http://localhost:3000 # 耗时约 25ms这个差距在开发阶段的影响非常大。想想你平时的开发流程改完代码保存等 nodemon 重启服务手动刷新浏览器。如果你的服务启动要花 800ms那么每次改动循环大约是 1-2 秒如果启动只要 60ms那么这个循环几乎是无感的。Bun 自己的--hot模式还支持模块级热更新也就是说你的模块状态可以保留改完代码只重新执行被依赖的部分不用整个进程重启。但这里我也要泼一盆冷水生产环境根本不在乎冷启动速度。生产环境的应用通常会保持长驻运行不会频繁重启。真正影响生产体验的是单请求延迟和吞吐量这两方面 Bun 有优势但远没有冷启动那么悬殊。而且如果你跑的是 Kubernetes 集群Pod 冷却启动慢一点不是问题因为你可以通过水平扩展来弥补。3.2 包管理器对比bun install 为什么那么快Bun 最被称道的另一个功能就是它的包管理器bun install。我拍着自己的 200 个依赖的项目实测npm install 需要 18 秒左右pnpm install 需要 9 秒而 bun install 只要 2 秒。为什么差距这么大原因有三个。第一个是全局缓存。Bun 会把下载过的包缓存到一个全局目录如果缓存命中本地解压就行完全不用走网络。第二个是并发下载。npm 的下载策略是相对保守的Bun 则会把所有依赖的下载任务同时丢出去最大程度利用带宽。第三个是协议优化。Bun 对 npm registry 的交互做了很多优化减少不必要的 metadata 请求。node_modules 目录的依赖解析用是全局的安装缓存方案让你在不同项目之间安装依赖时能复用同一份压缩包。不过需要注意一点bun install生成的是bun.lockb文件这个文件是二进制格式不能直接用文本编辑器查看 diff。如果你的团队需要 code review 依赖变更这一点会很不舒服。我记得 Bun 后来也支持了--yarn模式去生成兼容的 lockfile但不推荐在生产环境混用两套 lockfile 逻辑容易出问题。3.3 运行时 API 与兼容性矩阵我整理了一个实际项目中比较关心的对比表不是那种官方文档的完整列表而是从“会不会影响我迁移”的角度来看对比维度Node.jsBun迁移影响JavaScript 引擎V8JavaScriptCore极少数场景下有行为差异TypeScript 支持22.6 实验性支持原生支持开箱即用Bun 优势明显HTTP 服务http 模块回调风格Bun.serveWeb Fetch 风格如果用了框架则无感包管理器npm/pnpm/yarnbun install快但 lockfile 格式不同测试工具node:test / jest / vitestbun test 内置API 类似 jest热重载需 nodemon 等bun --hot 内置Bun 优势明显原生模块node-gyp (V8 ABI)部分支持需重编译大坑需评估.env 加载需 dotenv原生支持Bun 方便打包器需 webpack/vitebun build 内置Bun 够用但插件生态弱从表格可以看出Bun 在很多开发体验相关的维度上是占优的但原生模块和 API 兼容性这两个方向依然是它最大的风险点。我在实际迁移中还发现一个细节Bun 对 npm 包的exports字段的处理方式比 Node 更严格这意味着某些在 Node 下能跑的糊逼写法在 Bun 下会直接报错。这算好事还是坏事从工程规范的角度是好事但如果你是接手一个写得很随意的老项目迁移时可能会被一堆报错淹没。4. 实操把一个小项目从 Node 迁移到 Bun4.1 安装 Bun包含常见报错的完整处理先说说怎么装 Bun。官方推荐的方式是执行这个命令curl -fsSL https://bun.sh/install | bash这个脚本默认会把 Bun 装到~/.bun/bin并在 shell 配置里加一行 PATH。如果你想装到指定目录可以用环境变量BUN_INSTALLexport BUN_INSTALL$HOME/.bun curl -fsSL https://bun.sh/install | bash如果你用的是 Windows那就需要走不同路线了。Bun 在 Windows 上的支持仍然处于比较初级的阶段官方现在提供的是基于 WSL 的方案。我的建议很直接如果你主力机是 Windows开发阶段可以先在 WSL2 里面用 Bun或者干脆等一等。Bun 的 Windows 原生版本还在打磨中目前跑起来经常遇到各种诡异的问题不值得在生产环境上冒险。安装过程可能遇到的报错我在第 5 节详细讲这里只提醒一个关键点装完之后执行bun --version如果系统提示找不到命令大概率是 PATH 没生效执行source ~/.bashrc或者重新打开终端就行。升级 Bun 也非常简单它自己提供了内置的升级命令bun upgrade这个命令不需要你反复去官网下载新版本直接一键搞定。Bun 的开发团队更新频率很高大概每隔一两周就会发一个版本所以保持更新是很有必要的——他们修 bug 的速度快但引入新 bug 的速度也不慢。4.2 迁移实战一个 Express 风格服务的三种写法对比我拿一个最典型的场景来演示一个简单的待办事项 API带内存存储和 JSON 响应。首先看 Node Express 的经典写法// server.express.js const express require(express); const app express(); app.use(express.json()); const todos []; app.get(/todos, (req, res) { res.json(todos); }); app.post(/todos, (req, res) { const todo { id: todos.length 1, title: req.body.title }; todos.push(todo); res.status(201).json(todo); }); app.listen(3000, () { console.log(Server running at http://localhost:3000); });这是 Node 原生、不使用框架的写法// server.node.js const http require(http); const todos []; const server http.createServer((req, res) { res.setHeader(Content-Type, application/json); if (req.method GET req.url /todos) { res.end(JSON.stringify(todos)); return; } if (req.method POST req.url /todos) { let body ; req.on(data, (chunk) { body chunk; }); req.on(end, () { const todo { id: todos.length 1, title: JSON.parse(body).title }; todos.push(todo); res.statusCode 201; res.end(JSON.stringify(todo)); }); return; } res.statusCode 404; res.end(JSON.stringify({ error: Not Found })); }); server.listen(3000, () { console.log(Server running at http://localhost:3000); });你现在可以直接运行这个 Node 原生版本用node server.node.js启动。然后我们来看 Bun 的原生写法你会发现代码量大幅度减少而且用的是更现代化的 Fetch API 风格// server.bun.js const todos []; const server Bun.serve({ port: 3000, async fetch(req) { const url new URL(req.url); if (req.method GET url.pathname /todos) { return Response.json(todos); } if (req.method POST url.pathname /todos) { const { title } await req.json(); const todo { id: todos.length 1, title }; todos.push(todo); return Response.json(todo, { status: 201 }); } return Response.json({ error: Not Found }, { status: 404 }); }, }); console.log(Server running at http://localhost:${server.port});Bun 的版本用Response.json和req.json()直接处理 JSON不需要自己拼字符串也不需要手动设置Content-Type。代码看起来清爽很多。如果你已经写了 Express 服务也完全可以在 Bun 下直接跑 Express 吗答案是能跑但不推荐。Bun 兼容了 Node 的http模块Express 在 Bun 下一般能正常运行但性能优势不明显——因为你用了 Express 就等于走了一遍 Node 兼容层Bun 原生的性能优势发挥不出来。如果你真想发挥 Bun 的性能最好直接用Bun.serve或者考虑 Elysia 这样的原生 Bun 框架。4.3 TypeScript 支持不需要配置的快乐在 Node 下用 TypeScript 是一件需要配置的事情。早期的方案是ts-node跑得慢不说配置还麻烦。后来大家转向tsx顺便还会感叹一下 “如果 Node 原生支持 TypeScript 该多好”。Bun 里可以直接运行.ts文件不需要任何配置也不需要安装额外的依赖。它会在运行时把 TypeScript 类型擦除掉只保留 JavaScript 逻辑。举个例子你随手写一个hello.tsinterface User { name: string; age: number; } function greet(user: User): string { return Hello, ${user.name}! You are ${user.age} years old.; } console.log(greet({ name: Alice, age: 30 }));在 Node 下你需要先npx tsc hello.ts编译再运行或者装ts-node去运行在 Bun 下你直接bun hello.ts就能看到输出了。这意味着类型检查不是运行时行为而是编译期行为所以你写的时候如果类型报错了运行还是好好的——这对开发效率来说完全是正向体验。唯一的坑是Bun 目前对tsconfig.json里一些高级选项比如paths别名的解析和 Node 不一定完全一致如果项目里用了大量路径别名迁移过来要留意一下。4.4 从 package.json 到 bun 项目的平滑迁移步骤如果你确定要把一个 Node 项目迁到 Bun我建议按这个顺序来而不是一上来就bun install第一步备份当前环境。把当前node_modules和package-lock.json复制一份存档确保随时能回滚。第二步安装 Bun 并测试基础运行。先跑一个最小的 TypeScript 文件验证环境没问题。第三步用bun install重新安装依赖。注意Bun 会生成自己的bun.lockb文件。如果项目里有老的package-lock.json建议先删掉再安装避免两套 lockfile 之间的冲突。第四步逐个替换底层 API。如果项目里直接用了http.createServer改成Bun.serve如果用了fs.readFile的回调写法可以改成Bun.file()的异步流式写法体验会更好。第五步跑测试。如果你的测试用的是 jest建议先看看能否换成bun test。它的 API 和 jest 很接近大多数情况下改动量不大。如果项目里有大量 mock 逻辑那可能还是先保留 jest 更稳妥因为 jest 生态的 mock 能力强太多了。第六步手动回归核心流程。不要只跑测试就完事一定要实际开服务、发请求、连数据库把核心链路走一遍。很多运行时差异是单测测不出来的。5. 常见问题排查与踩坑实录5.1 Bun 安装失败的几种典型报错我在安装和使用 Bun 的过程中遇到过不少报错这里挑几个典型的记录下来希望你能少走弯路。报错一curl: command not found这个最基础了你的系统里没有 curl。在 Linux 上可以用apt install curl或yum install curl安装在 macOS 上一般自带 curl。报错二Permission denied 或者 EACCES执行安装脚本的时候提示权限不足。原因是脚本默认写入~/.bun目录而某些系统环境变量配置导致目录权限不对。最简单的方式curl -fsSL https://bun.sh/install | bash # 如果报 EACCES可以指定自定义目录 export BUN_INSTALL$HOME/.local curl -fsSL https://bun.sh/install | bash报错三GLIBC_2.29 not found这个我印象太深了。Bun 从某个版本开始要求系统 GLIBC 版本不低于 2.29这直接排除了一批老版本的 CentOS 7、Ubuntu 18.04 之类环境。解决办法是升级系统到比较新的发行版或者用 Docker 镜像跑 Bun。如果你在用 Docker可以基于oven/bun官方镜像来构建FROM oven/bun:1 WORKDIR /app COPY package.json bun.lockb ./ RUN bun install COPY . . CMD [bun, run, server.ts]报错四Windows 下运行报错无法启动如果你的 Windows 是原生环境没有 WSL那么大概率会遇到各种奇怪问题。我建议你在 Windows 上想尝试 Bun一定要先装 WSL2然后在 WSL 的 Ubuntu 里安装 Bun。这是目前官方支持的唯一推荐路径。5.2 迁移到 Bun 后的行为差异排查我实际遇到的一个血泪教训是某个项目迁到 Bun 之后环境变量读不到了。排查了半天才发现Bun 只在启动时读取.env文件但我的.env里有一个 key 的名称带点号比如database.host这在 Node 的 dotenv 里是允许的但在 Bun 的默认解析逻辑里会被忽略。解决方案是改用连字符或者下划线命名或者在代码里显式用process.env去访问。还有一个很常见的坑是动态 import 的处理方式。Bun 在处理循环依赖和动态导入的时候语义和 Node 略有不同。尤其是用 CommonJS 和 ESM 混合的老项目迁移过来之后经常遇到ERR_MODULE_NOT_FOUND问题。这个没有特别好的通用解法只能一个个改 import 路径。另外我把之前整理过的一个行为差异速查表放在下面供你在排查时参考现象原因建议启动后读取不到 .envBun 只读根目录 .env解析规则更严格确认 key 命名避免特殊字符原生模块报错node-gyp 编译产物不兼容换纯 JS 替代库或等 Bun 适配node:test相关代码报错Bun 优先使用内置 bun:test检查 import 来源是 node: 还是 bun:打包时依赖缺失Bun 对 exports 字段处理更严格补全 package.json exports 字段并发请求竞态行为不一致JSC 的事件循环与 V8 微任务细节不同尽量避免依赖执行顺序的代码5.3 与 pnpm/npm/yarn 的兼容性问题我见过不少人bun install之后还把项目推给 CICI 里继续用npm install结果 lockfile 变了导致依赖解析失败。这里提醒一点不要让 Bun 和其他包管理器混用。如果你的项目用了 pnpm 的 workspace 功能迁移到 Bun 要特别注意。Bun 的 workspace 支持目前比 pnpm 弱一些尤其是处理peerDependencies时的行为有差异。如果你用了 pnpm 独有的pnpm.overrides或pnpm.peerDependencyRules这些字段 Bun 是不认的。一种比较稳妥的做法是小项目、新项目直接用 Bun 全流程管理包括本地开发、CI 安装、测试执行老项目、大项目先单独开一个分支做兼容性验证在没有完全验证通过之前不要贸然切换。Bun 的兼容性在快速提升是事实但生产环境的稳定性永远是第一位的。5.4 我建议的“共处”模式Bun 不一定要全用最后分享一个我自己的实际用法。我并没有把全部项目都迁到 Bun而是只在新项目或者纯前端工具链的构建环节使用。Bun 的bun build打包速度确实比 webpack 快很多有时候只是构建一次项目里就能明显感受到效率提升。典型做法是在 package.json 里把 scripts 的构建命令从 webpack 换成 bun{ scripts: { dev: bun --hot server.ts, build: bun build ./src/index.ts --outdir ./dist, test: bun test } }这种方式既保留了 Bun 的开发效率又不用承担把老项目整体迁移的风险。如果你问我的个人建议即使你暂时不把核心业务运行在 Bun 上也值得在工具链层面尝试它。等它的兼容性进一步成熟再从边缘项目开始逐步替换这样整个过程会比较平滑。6. 我的结论Bun 会取代 Node.js 吗直接说结论短期内不会长期有可能但“取代”这个词太绝对了。从技术生态的角度看Node.js 最大的优势不是某项技术指标而是它背后那个庞大的、经过十年验证的社区。企业的技术选型最看重的是确定性一个库在 Node 上跑得好好的生产环境稳定运行了五年你让我为了两倍的冷启动速度去换运行时老板不会同意的运维也不会同意的。这种惯性不是技术优势能轻易撼动的而是一种组织层面的信任。但另一方面Bun 所带来的“快”和“全”并不是无意义的。它实际上把 JavaScript 工具链的整体体验拉高了一个层次。我记得第一次在 Bun 上写 TypeScript 的时候完全没有配置、没有编译延迟、瞬间就跑起来了那种顺畅感确实改变了我对“JavaScript 开发工具”的认知。如果 Bun 能继续保持现在的迭代速度把兼容性做到更完善那么它在未来两到三年里很有可能成为新项目的默认选择之一。从历史经验来看“取代”很少真正发生更常见的是“共生”。就像现在 Docker 并没有取代虚拟机Kubernetes 也没有让 Docker 消失一样Bun 和 Node.js 很可能会长期共存。Bun 适合开发体验要求高、团队痛恨配置、喜欢拥抱新工具的项目Node.js 适合生产环境稳定优先、生态依赖深、团队需要大规模协作的项目。两者不是非此即彼的敌人而是技术光谱上两个不同的选择。我个人现在的选择是新项目用 Bun 做开发和构建核心生产环境继续用 Node等 Bun 的兼容性认证更完善后逐步扩大使用面。这既让我享受到了新工具的便利又不会因为激进而付出不必要的代价。