Node概况

201 阅读5分钟

Node概况

JavaScript在浏览器和服务器端都可以进行,其区别主要是,在服务器端运行的JavaScript没有DOM和BOM等操作

1.Node的特点

  • 单线程,Node保持了JavaScript中的单线程的特点
  • 异步I/O,利用JavaScript的eventLoop事件循环机制
  • 事件与回调函数,事件和回调函数是处理异步的有效的方式
  • 跨平台,因为在window和Node.js中间加了libuv中间层,使得Node在window或者其他平台上的运行成为可能 node在开发的过程中,会引入不同的模块,包括核心模块和第三方模块等。

2.模块分类

(1)核心模块
  • C/C++内建模块,是底层模块,可以预先编译成.node文件,然后调用process.dlopen()方法加载执行,需要通过JavaScript核心模块进行调用。
  • javascript核心模块,指的是fs、os和http等模块,其优先级仅次于缓存加载,它在node的源代码编译过程中已经编译为了二进制代码,加载速度最快。其主要作用是,作为内建模块和自定义模块的枢纽,或者直接是纯粹的功能。
(2)自定义模块

是特殊的文件模式,可能是一个文件或者包的形式,这类模块的查找是最费时的,也是所有查找过程中最慢的一种。 其查询规则是:

  • 当前文件目录下的node_modules目录;
  • 父目录下的node_modules目录;
  • 父目录下的父目录下的node_modules目录;
  • 沿着路径向上逐级递归,直到根目录下的node_modules目录。 它的生成方式与JavaScript的原型链或作用域链的查找方式十分类型。可以得知,文件路径越深,那么模块查找耗时会越多,这就是自定义模块加载速度慢的原因。

注:前后端公用模块,浏览器端的JavaScript需要经历从同一个服务器分发到多个客户端执行,而服务器端JavaScript则是相同的代码需要多次执行,前者瓶颈在于带宽,后者的瓶颈在于CPU和内存等资源。

注:在node模块加载的过程中,主要采用的是CommonJs的方式,主要调用的api是require、exports和module。

3.异步I/O

单线程同步编程模式会因阻塞I/O导致硬件资源得不到更优的使用。多线程编程模式也因为编程中的死锁、状态同步等问题让开发变得有难度。 Node在两者之间权衡取出最优解,利用单线程,远离多线程死锁、状态同步等问题;利用异步I/O,让单线程远离阻塞,以更好的利用CPU。
在这里需要注意node.js的定时器:

  • setTimeout
  • setInterval
  • setImmediate
  • process.nextTick

4.V8内存问题

image.png
其中,V8中的内存在默认条件下,如果一直分配内存,在64位系统和32位系统下会分别只能使用约为1.4GB和0.7GB。而新生代在64位系统和32位系统上分别为16MB和8MB,仅仅占其中的一小部分。

  • 新生代,新生代中存放的是生存时间短的对象,由副垃圾回收器回收 新生代用Scavenge算法来处理,就是把新生代空间对半划分为两个区域,一半是对象区域,一半是空闲区域。新加入的对象会被存放到对象区域,当对象区域快被写满的时候,就执行一次垃圾清理操作。副垃圾回收器会把存货的对象复制到空闲的区域中,并有序的排列起来,复制过程,也相当于内存整理操作。

完成复制后,对象区域与空闲区域进行角色翻转,角色翻转操作还能让新生代中的这两块区域无限重复使用下去。

也正是因为新生区的空间不大,所以很容易被存活的对象装满整个区域。为了解决这个问题,JavaScript 引擎采用了对象晋升策略,也就是经过两次垃圾回收依然还存活的对象,会被移动到老生区中。

  • 老生代,老生代中存放的生存时间久的对象,由主垃圾回收器回收 标记-整理(Mark-Compact)标记 - 清除(Mark-Sweep) 的引申。标记-清除是遍历调用栈,标记其中没有被引用的变量,然后将其标记,在接下来的垃圾清除过程中,清除掉标记的数据。而,标记-整理,不直接对可回收的对象进行清理,而是让其有存货的对象都向一端移动,然后直接清理掉端边界以外的内存。

5.buffer对象

Buffer是一个典型的JavaScript与C++结合的模块,它将性能相关的部分用C++实现,将非性能相关的部分用JavaScript实现。
上面也简单介绍了V8的内存问题,但是,buffer的内存不是在V8的堆内存中的,而是在Node的C++层面实现内存申请的。
因为处理大量的字节数据不能采用需要一点内存就向操作系统申请一点内存的方式,这会造成大量的内存申请的系统调用,对操作系统有一定的压力。为此Node在内存的使用上采用的是在C++层面申请内存、在JavaScript中分配的策略。
根据8KB为界限,将Buffer划分为:

  • 小对象
  • 大对象

参考书籍:
《 深入浅出NODEJS 》( 朴灵 )