极简 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 官网的定义就这么简单,但也可以看出几个最重要的特征

  1. Node.js 不是一门语言,是一个运行时,和浏览器更像,只不过运行在服务端
  2. 这个运行时的方言是 JavaScript(不包含 BOM、DOM API,增加了 Stream、网络等 API)
  3. 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,所以有了多线程的性能优化手段,但学习操作系统的时候我们就知道

  1. 操作系统创建线程和切换多和线程上下文需要一定的开销
  2. 因为多线程带来的执行堆栈是要占用内存的
  3. 多线程变成面对的死锁、状态同步等问题会增加使用的复杂性

上面的代码要么阻塞整个进程,要么使用了多线程,如果进程不等待 I/O 结果,直接处理后续任务就是非阻塞 I/O,这样可以不用浪费 CPU

db.query('select * from...', function (result) {
// 消费 result
});

在 Promise、async|await 没有的年代,回调是异步的通用处理方式

进程如何获知异步 I/O 调用完成,触发回调函数呢?这就要靠 Event Loop 实现,也就是上面提到的事件驱动

这个图看起来非常复杂,有几个要点可以帮助理解

  1. 在 Node.js 中所有操作称之为事件,客户端的请求也是事件,所有事件维护在图中最左侧的事件队列中
  2. Node.js 主线程也就是图中间的循环就是 Event Loop,主要作用是轮训事件队列中是否存在事件
    1. 有非阻塞事件,按照先进先出原则依次调用处理
    2. 有阻塞事件,交给图中最右侧的 C++ 线程池处理,线程池处理完成后把结果通过 Event Loop 返回给事件队列
    3. 进行下一次循环
  3. 一个请求所有事件都被处理,把响应结果发给客户端,完成一次请求

这样一个请求 - 响应模型就完成了,如果在 Event Loop 中包含同步的 CPU 密集操作,就会阻塞主线程

Node.js 性能真的高吗?

要回答这个问题首先需要了解几个基本常识

  1. CPU 运算远远快于 I/O 操作
  2. Web 是典型的 I/O 密集场景
  3. 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,交给底层完成,然后可以接着处理下一个请求了,快就快在

  1. 非阻塞 I/O
  2. Web 场景 I/O 密集
  3. 没多线程 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 实现非阻塞模型也会遇到一样问题

参考

  1. Node.js 作者 Ryan Dahl 介绍 Node.jsRyan Dahl 2009 JSconf - Node.js.pdf
  2. NGINX 如何实现高性能和可扩展性
  3. 深入理解 JavaScript Event Loop

极简 Node.js 入门 - Node.js 是什么、性能有优势?的更多相关文章

  1. Node.js入门-Node.js 介绍

    Node.js 是什么 Node.js 不是一种独立的语言,与 PHP,Python 等"既是语言优势平台"不同,它也不是一个 JavaScrip 框架,不同于 CakePHP,D ...

  2. Vue.js 入门 --- vue.js 安装

    本博文转载  https://blog.csdn.net/m0_37479246/article/details/78836686 Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据 ...

  3. js入门 关于js属性及其数据类型(详解)

    1. js的本质就是处理数据.数据来自于后台的数据库. 所以变量就起到一个临时存储数据的作用. ECMAScript制定了js的数据类型. 数据类型有哪些? 1. 字符串   String 2. 数字 ...

  4. js入门关于js‘i++’‘++i’和‘i--’‘--i’计算的问题

    一,i++和++i; i++是先赋值在运算,++i是先运算在赋值: 例如:var a=1 a++:在运算时是按照1计算的:但在下面再次出现时是按照2进行运算: ++a:在运算时是按照2计算的:在下面再 ...

  5. 极简 Node.js 入门 - 1.2 模块系统

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  6. 极简 Node.js 入门 - 1.3 调试

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  7. 极简 Node.js 入门 - 1.4 NPM & package.json

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  8. 极简 Node.js 入门 - 2.1 Path

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  9. 极简 Node.js 入门 - 2.2 事件

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

随机推荐

  1. BERT模型图解

    转载于 腾讯Bugly 发表于 腾讯Bugly的专栏 原文链接:https://cloud.tencent.com/developer/article/1389555 本文首先介绍BERT模型要做什么 ...

  2. day39 作业

    实现生产消费原理 from multiprocessing import Process,JoinableQueue import time import random def cooker(q): ...

  3. 为什么有时候人们用translate来改变位置而不是定位?

    translate()是transform的一个值. 改变transform或opacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)(复 ...

  4. Django的Cookie Session和自定义分页

    cookie Cookie的由来 大家都知道HTTP协议是无状态的. 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不 ...

  5. Mysql基础(八):MySQL 表的一对一、一对多、多对多问题

    将实体与实体的关系,反应到最终数据库表的设计上,将关系分为三种:一对一,一对多(多对一)和多对多,所有的关系都是表与表之间的关系; 一对一 一对一:一张表的一条记录只能与另外一条记录进行对应,反之亦然 ...

  6. IOS10 window.navigator.geolocation.getCurrentPosition 无法定位问题

    在iOS 10中,苹果对webkit定位权限进行了修改,所有定位请求的页面必须是https协议的. 如果是非https网页,在http协议下通过HTML5原生定位接口会返回错误,也就是无法正常定位到用 ...

  7. ShaderLab-坐标转换

    观察空间就是相机的空间 投影矩阵本质就是对x.y.z分量进行不同程度的缩放(z还做了平移),结果就是视锥体近切面远切面变成正方形.视锥体的中心在(0,0). (对于正交相机,这一步已经得到了立方体) ...

  8. day2:Number,tuple,str,list,set,dict

    # ### Number ( int float bool complex) 1.int 整型 (正整数 0 负整数)intvar = 1print(intvar) # type 获取值的类型res ...

  9. js自定义获取浏览器宽高

    /** * @description js自定义获取浏览器宽高 * * IE8 和 IE8 以下的浏览器不兼容 * window.innerWidth * window.innerHeight * * ...

  10. Python Ethical Hacking - BeEF Framework(1)

    Browser Exploitation Framework. Allows us to launch a number of attacks on a hooked target. Targets ...