极简 Node.js 入门 - Node.js 是什么、性能有优势?
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node
本文更佳阅读体验:https://www.yuque.com/sunluyong/node/what-is-node
定义
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine.
现在 Node.js 官网的定义就这么简单,但也可以看出几个最重要的特征
- Node.js 不是一门语言,是一个运行时,和浏览器更像,只不过运行在服务端
- 这个运行时的方言是 JavaScript(不包含 BOM、DOM API,增加了 Stream、网络等 API)
- Node.js 是靠 Chrome V8 引擎运行 JavaScript
对应到 Java 我们可以理解 Node.js 是 JDK,装上就能在服务端跑 JavaScript 代码了。
Chrome 和 Node.js 同样是 JavaScript 运行时,都使用了 V8 引擎,主要区别在于 V8 只实现了 ECMAScript 的数据类型、对象和方法,Chrome 运行时提供了 Window、DOM、BOM,而 Node.js 运行时提供了global、 Buffer、net 等模块
下面内容需要一些计算机基础知识,但看不懂并不影响 Node.js 的学习
事件驱动 & 非阻塞 I/O 是什么
在 Node.js 才诞生的时候大家总是充满了好奇,早期官网上的介绍要更多一些,主要说了 Node 最核心的两个特性:事件驱动、非阻塞 I/O
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
举个例子理解 Node.js 和之前大部分 web 应用编程区别,当读取数据库的时候会写出这样的代码
var result = db.query('select * from...');
I/O 是一个相对耗时较长的工作(这是后面讨论的前提),I/O 任务主要由 CPU 分发给 DMA 执行,等待数据库查询结果的时候进程在做什么?大部分时候就是单纯在等着而已
不同硬件设备 I/O 操作所花费 CPU cycles
Action Cost (CPU cycles)
L1 Cache* 3
L2 Cache* 14
RAM* 250
Disk 41,000,000
Network 240,000,000
这明显是在浪费 CPU,所以有了多线程的性能优化手段,但学习操作系统的时候我们就知道
- 操作系统创建线程和切换多和线程上下文需要一定的开销
- 因为多线程带来的执行堆栈是要占用内存的
- 多线程变成面对的死锁、状态同步等问题会增加使用的复杂性
上面的代码要么阻塞整个进程,要么使用了多线程,如果进程不等待 I/O 结果,直接处理后续任务就是非阻塞 I/O,这样可以不用浪费 CPU
db.query('select * from...', function (result) {
// 消费 result
});
在 Promise、async|await 没有的年代,回调是异步的通用处理方式
进程如何获知异步 I/O 调用完成,触发回调函数呢?这就要靠 Event Loop 实现,也就是上面提到的事件驱动

这个图看起来非常复杂,有几个要点可以帮助理解
- 在 Node.js 中所有操作称之为事件,客户端的请求也是事件,所有事件维护在图中最左侧的事件队列中
- Node.js 主线程也就是图中间的循环就是 Event Loop,主要作用是轮训事件队列中是否存在事件
- 有非阻塞事件,按照先进先出原则依次调用处理
- 有阻塞事件,交给图中最右侧的 C++ 线程池处理,线程池处理完成后把结果通过 Event Loop 返回给事件队列
- 进行下一次循环
- 一个请求所有事件都被处理,把响应结果发给客户端,完成一次请求
这样一个请求 - 响应模型就完成了,如果在 Event Loop 中包含同步的 CPU 密集操作,就会阻塞主线程
Node.js 性能真的高吗?
要回答这个问题首先需要了解几个基本常识
- CPU 运算远远快于 I/O 操作
- Web 是典型的 I/O 密集场景
- JavaScript 是单线程,但 JavaScript 的 runtime Node.js 并不是,负责 Event Loop 的 libuv 用 C 和 C++ 编写
很多语言是依赖的多线程解决高并发,一个线程处理一条用户请求,处理完成了释放线程,在阻塞 I/O 模型下, I/O 期间该用户线程所占用的 CPU 资源(虽然十分微量,大部分交给了 DMA)什么都不做,等待 I/O,然后响应用户,而且开启多个进程/线程 CPU 切换 Context 的时间也十分可观
就像饭店的服务员只负责点菜,如果给每个厨师都配一个服务员,服务员把客人菜单给大厨后就玩手机等着一样,你是老板你也生气,况且不同于饭店大厨工资高于服务员,在计算机世界,CPU 资源比 I/O 宝贵的多
说 Node.js 在高并发、I/O 密集场景性能高,也就是 Web 场景性能高主要也是解决这个问题,没必要一个厨师配一个服务员,整个饭店说不定一个服务员就够了,剩下的钱可以随便做其它事情
用户请求来了, CPU 的部分做完不用等待 I/O,交给底层完成,然后可以接着处理下一个请求了,快就快在
- 非阻塞 I/O
- Web 场景 I/O 密集
- 没多线程 Context 切换开销,多出来的开销是维护 EventLoop
其它场景 NodeJS 性能确实不高,甚至非常低下,感兴趣可以看一下 Apache(多进程) 和 Nginx(事件驱动) 对比,现在大型 web 应用普遍是 Nginx 在最前面做负载均衡服务器、静态资源服务器,Apache 在下一层做实际 Web Server,响应动态请求
因此 Node.js 在 I/O 密集的 Web 场景相对于使用多进程模型语言有性能优势,这个优势不是来源于语言,而是操作系统实现,Java 按照这种模型实现性能一样很高
得益于 V8 的优化和 C/C++ 拓展,Node.js 执行 CPU 密集任务性能并不差,但如果长时间进行 CPU 运算会阻塞后续 I/O 任务发起,用 Java 实现非阻塞模型也会遇到一样问题
参考
- Node.js 作者 Ryan Dahl 介绍 Node.jsRyan Dahl 2009 JSconf - Node.js.pdf
- NGINX 如何实现高性能和可扩展性
- 深入理解 JavaScript Event Loop
极简 Node.js 入门 - Node.js 是什么、性能有优势?的更多相关文章
- Node.js入门-Node.js 介绍
Node.js 是什么 Node.js 不是一种独立的语言,与 PHP,Python 等"既是语言优势平台"不同,它也不是一个 JavaScrip 框架,不同于 CakePHP,D ...
- Vue.js 入门 --- vue.js 安装
本博文转载 https://blog.csdn.net/m0_37479246/article/details/78836686 Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据 ...
- js入门 关于js属性及其数据类型(详解)
1. js的本质就是处理数据.数据来自于后台的数据库. 所以变量就起到一个临时存储数据的作用. ECMAScript制定了js的数据类型. 数据类型有哪些? 1. 字符串 String 2. 数字 ...
- js入门关于js‘i++’‘++i’和‘i--’‘--i’计算的问题
一,i++和++i; i++是先赋值在运算,++i是先运算在赋值: 例如:var a=1 a++:在运算时是按照1计算的:但在下面再次出现时是按照2进行运算: ++a:在运算时是按照2计算的:在下面再 ...
- 极简 Node.js 入门 - 1.2 模块系统
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 1.3 调试
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 1.4 NPM & package.json
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 2.1 Path
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 2.2 事件
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
随机推荐
- if-else和三目运算符 ? : 的对比
今天的地铁思考让我想起一个之前学C语言的时候一直没有验证的事情:既生瑜何生亮? 平时写代码的时候,似乎并没有太多的关注我应该选用什么条件判断语句,感觉判断条件或者两条支路语句复杂就本能地if-else ...
- 【网鼎杯2018】fakebook
解题过程: 首先进行目录扫描,发现以下目录: user.php.bak login.php flag.php user.php robots.txt user.php.bak猜测存在源码泄露. 查看源 ...
- 机器学习实战基础(三十):决策树(三) DecisionTreeRegressor
DecisionTreeRegressor class sklearn.tree.DecisionTreeRegressor (criterion=’mse’, splitter=’best’, ma ...
- Flask 基础组件(十):中间件
from flask import Flask, flash, redirect, render_template, request app = Flask(__name__) app.secret_ ...
- node最简单的本地服务搭建
**1.首先需要安装node** [node下载链接](http://nodejs.cn/download/)**2.需要安装http的镜像文件** npm install http-server - ...
- 手把手从零开始---封装一个vue视频播放器组件
现在,在网页上播放视频已经越来越流行,但是网上的资料鱼龙混杂,很难找到自己想要的,今天小编就自己的亲身开发体验,手把手从零开始---封装一个vue视频播放器组件. 作为一个老道的前端搬砖师,怎么可能会 ...
- Apache Avro & Avro Schema简介
为什么需要schema registry? 首先我们知道: Kafka将字节作为输入并发布 没有数据验证 但是: 如果Producer发送了bad data怎么办? 如果字段被重命名怎么办? 如果数据 ...
- Go Pentester - HTTP CLIENTS(2)
Building an HTTP Client That Interacts with Shodan Shadon(URL:https://www.shodan.io/) is the world' ...
- JAVA集合一:ArrayList和LinkedList
JAVA集合一:ArrayList和LinkedList 参考链接: HOW2J.CN 前言 这几篇博客重点记录JAVA的几个重要的集合框架:ArrayList.LinkedList.HashMap. ...
- 微信小程序-点餐系统
一.前言说明 博客声明:此文链接地址https://www.cnblogs.com/Vrapile/p/13353264.html,请尊重原创,未经允许禁止转载!!! 1. 主要功能 (1)后台定义分 ...