Skip to main content

Node

Node.js是什么

Node.js是一个基于Chrome V8引擎的JavaScript运行环境。Node.js使用了一个事件驱动的、非阻塞式I/O的模型,轻量又高效,它的底层是用C/C++编写的。这是Node.js的官方描述,对前端开发人员来说,想要搞清楚其中所包含的“引擎”“运行环境”“事件驱动”以及“非阻塞I/O模型”到底是什么意思,并不是一件容易的事情。

那么Node.js到底是什么?我们先用一个类比的示例来进行解释。比如,有人向你发送了一个扩展名为docx的文档,你想要查看其中的内容,于是打开记事本,把该文档拖到记事本的窗口里,然后就看到了一大堆乱码。这是因为记事本程序并不能识别这种格式的文档,你需要先安装Microsoft Office 2007以上版本的软件,然后用Word程序打开,这样才能看到正确解码的内容。

如果把示例中的docx文件看作程序,那么Word就是它的运行环境,这就像JavaScript程序与浏览器的关系一样。如果你了解过现代浏览器的结构,就会知道其中包含了JavaScript引擎。

以前,想要查看docx文件的内容,几乎只能依赖于Microsoft Office,后来金山公司也推出了办公软件工具WPS Office,它也能够解释和运行docx文件,于是docx文件就有了多个可运行环境,而Node.js对于JavaScript语言的意义也是如此。

为了更加直观地理解运行时的概念,你可以尝试一个有趣的实验,自己创造一种简单的编程语言,规定一些简易的语法,然后使用JavaScript来编写能够解释这些语法的代码。

例如,用自创的语言编写一些简单的程序,最后通过Node.js运行JavaScript程序,并在程序中用Node.js提供的文件读写接口(File API)读入你用自创的编程语言编写的程序,看看它能否被正确地解释和执行。待你了解了JavaScript是如何完成对自创编程语言的解释和执行的,自然就能明白在Node.js运行环境中,C/C++对JavaScript脚本做了什么事情。

Node.js能做什么

在Node.js的诸多功能中,与前端开发人员关系最紧密的就是创建Web服务器和本地文件的读写能力。

创建高性能Web服务器

许多Node.js的初学者应该都见过那段只用了不到10行代码就建立了一个Web服务器的经典示例。尽管对于前端开发人员而言,他们依然需要学习基本的Web服务器知识,才能更加得心应手地进行服务端开发,但与配置Apache或Nginx来实现同样的功能相比,这样的学习成本已经非常低了,毕竟前端开发人员可以使用自己最熟悉的JavaScript语言来构建应用。

另一方面,在Node.js中,代码可以与各类数据库进行交互,这就意味着前端工程师可以直接使用JavaScript语言编写与数据库进行交互的代码(尽管在大型应用中并不推荐这样做),且编写业务逻辑代码时,Node.js与其他后端语言没有明显的差别,因此前端开发人员不用切换开发语言就可以掌握全栈开发的技能。

由于Node.js底层使用的是异步非阻塞的I/O机制,因此它更适合于I/O密集、少量业务逻辑和计算消耗的场景。尽管解释型脚本语言本身并不适合执行计算型任务,但Node.js底层是由C/C++代码编写的,并且提供了JavaScript代码层与C/C++代码交互的接口,面对计算密集型任务时,Node.js只需要作为启动脚本调用底层C/C++程序来完成计算密集型任务就可以了。

服务端执行的任务大体可分为读写密集型任务和计算密集型任务。对于读写密集型任务而言,CPU更多的时间是在等待磁盘读写,使用率并不高,在Web服务器上进行的网络通信、信息传输和磁盘读写等都属于读写操作,它对磁盘的响应速度和传输效率有着更高的需求。

相较而言,计算密集型任务对CPU的运算能力要求更高,但对磁盘读写造成的性能负担很小,计算过程中通常也不需要与I/O接口进行交互,可直接、高效地在内存中执行,这类任务的计算过程通常比较复杂,例如需要实现某些加密算法或者矩阵计算等。

大型架构的后端技术选型需要考虑的因素更为复杂,Node.js设计之初并没有准备承担这项任务,就连Node.js之父Ryan Dhal自己也说,在面对大型服务端应用开发时,Node.js的开发体验不如Go语言。

但是,全世界目前有600多种编程语言,没有任何一种语言能够解决所有问题,语言只是承载和传递程序设计思想的媒介,如何为目标场景选择一项合适的技术,或许是开发人员更应该关注的问题。

当你在前端领域有一定的积累时,很多前辈都会推荐你继续学习Java或C++等更为完备也更为复杂的语言,这样做的目的并不仅仅是扩展能力边界,更多的是希望你能够跳出一种编程语言的束缚,学习和体会编程语言背后的思想。

本地文件的读写功能

文件读写功能的底层所要解决的问题其实有很多。如果文件里的内容比较多,读入内存的过程比较耗时,应该怎么处理呢?是等待读入操作完成还是先去执行其他任务?如果客户端请求的资源是一部高清电影,文件比程序可用的总内存还大,那么该文件是否就一定无法读取了呢?

Node.js的fs模块几乎为每个文件操作接口都提供了同步和异步两种方法,同时也支持以流的方式对读写过程实现更细粒度的控制,甚至还可以监测指定文件或文件夹的变动。文件可读写意味着开发人员可以通过程序分析另一个程序中文件的内容,并对其进行检查和纠错,甚至可将其编译成另一种语言,这便是前端工程化的能力基石。