Node.js不是语言,它没在浏览器里跑过,可前端全靠它活着。
我最近看懂了一件事:原来JavaScript离开浏览器,根本不是换了个地方干活,而是彻底换了套活法。以前只管写页面,现在得懂终端、文件、端口,甚至系统调用。这不是升级,是重新学怎么跟电脑说话。
浏览器里的JS,看着自由,其实浑身是锁。window、document、fetch全靠浏览器给,V8引擎自己啥也不管。它就像个只会念稿的演员,剧本、灯光、音响都得别人搭好。你让它读个本地文件?不行。开个服务器?没这功能。不是语法不行,是它压根没被允许干这些事。
Node.js干的,就是给JS配了一套全新的“剧组”。V8还是那个V8,但后台换成了libuv——一个能和操作系统直接掰手腕的底层库。它让JS第一次能真正碰磁盘、开网络、管进程。没有window,有global;没有DOM,有fs和http模块;不用等浏览器加载完才能动,你自己写一行node index.js,它就真开始跑了。
很多人说Node是后端,其实它连后端都算不上。它只是个“能跑JS的壳”。Express、Koa那些才是框架。Node本身连路由都不管,就干三件事:装好V8,接通系统I/O,再塞进一堆C++写的模块供JS调用。它不聪明,但够快、够轻、够直接。

安装Node也没那么玄。LTS版就像手机系统更新,稳定、少bug、企业用得多;Current版像测试版,新功能多,但可能今天好使明天崩。我没折腾源码编译,直接下了nvm,想切版本输个命令就行。以前怕装错搞得整个系统乱,现在一个命令就来回切,连重装都不用。
运行JS也分三种状态。敲node回车,进去就是REPL,输啥立马回啥,适合试小片段。写个index.js再node index.js,就开始走CommonJS那一套:require进来,module.exports出去,模块之间靠路径连。最常用的是npm run dev,表面是跑命令,背后是Webpack/Vite这些工具在Node上转着圈打包、热更新、启本地服务。你敲的那行命令,早被封装了十层。
终端也不只是黑框框。pwd是看我在哪,ls是看有啥文件,netstat -ano | findstr :3000能立刻揪出占着3000端口的进程号。以前总以为前端不用碰这些,后来发现,连热更新失败都可能是端口被占了,不查终端根本找不到原因。
Node的设计,全是为了一件事:别卡住。单线程不是偷懒,是怕线程切换反而更慢。所有异步API都默认走事件循环,readFile比readFileSync快,不是因为代码高级,是因为它把活扔给操作系统,自己去干别的。遇到CPU密集任务?那就开worker_threads,或者干脆启个子进程,别堵着主线程。
我试着debug过process.nextTick()和Promise.then()谁先执行。结果发现nextTick永远插队在Promise前面,哪怕Promise是同步resolve的。这才明白,微任务队列里还分个三六九等。再往下追fs.readFile,能从JS层一路看到C++ binding,再到libuv封装,最后进到Linux的epoll里。原来一句代码背后,是四层系统在接力干活。
npm包数量早过了三百万,但真正天天用的就那几十个。eslint检查代码,prettier格式化,nodemon自动重启,vite启动快得像没启动。它们全靠Node撑着。没有Node,前端工程化就是纸上谈兵。
有人问学Node要学多久。我说,不学完,就学够用。能写个脚本批量改文件名,能看懂package.json里scripts怎么串起来,能查出端口冲突在哪,这就够了。太深的原理,用到再说。
现在我写前端,会下意识想:这段逻辑,能不能抽出来用Node跑?那个接口mock,能不能直接起个本地服务?原来JS真的可以到处跑,只要给它配对的环境。
Node.js不是后端,也不是前端。它是JS能落地的那块地。