laihuamin / learn-record

这里是笔者补充学习笔记的地方,以前看书记录的很少,经常忘记,所以将看过的重点记下来

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

《深入浅出的nodeJS》第二章(1)

laihuamin opened this issue · comments

JS的变迁

JS变迁.png
JS从一个工具到组件库,再到前端框架,最后组合成前端应用。这个过程中也暴露了JS的缺陷:没有模块系统。只有杂乱无章的<script>标签的引入。

commonJS规范

commonJS规范涵盖了模块、二进制、BUffer、字符集编码、I/O流、进程环境、文件系统、套接字、单元测试、web服务器网关接口、包管理等。

node与commonnJS的关系

commonJS关系.png

commonJS模块规范

commonJS模块规范分为模块定义,模块引用和模块标识三个部分。

module-define.png.

三个部分分别是图中的exports、require、module。

引入模块的三个步骤

1、路径分析
2、文件定位
3、编译执行

node模块分类

node模块分为两类:核心模块和文件模块

node的核心模块大多在源代码里,所以在node编译的过程中,会被编译成二进制文件,存放在内存中,所以文件定位和编译执行可以被省略,路径分析优先级比文件模块高。速度快。(优先从缓存中加载)

文件模块编译的时候需要进行路径分析、文件定位和编译执行,速度比核心模块慢。

node对于标识符的分析

1、核心模块标识符,如果这个模块是核心模块,不需要进行路径分析和文件定位
2、路径文件标识符,该文件是由绝对路径或者相对路径来表示的,node会把编译加载的模块放在内存中,所以二次加载速度很快,该方式由于为node指明了目录,所以速度慢于核心模块
3、自定义模块,指的是包或者文件,没有路径指明,所以这种模块的查找时间是最长的

路径分析的规则

1、当前目录的node_modules中查找
2、如果没有找到,向父目录的node_modules中查找
3、直到查到根目录的node_modules为止。

文件定位

文件定位分为文件扩展名分析和包或者目录分析。

  • 文件扩展名分析:

如果一个文件没有扩展名,node会根据.js,.node,.json的顺序查找。
所以,当一个文件是.node或者.json的时候,最好把扩展名加上,可以加快查找速度。
也可以同步配合缓存,来加快文件的解析。

  • 包或者目录分析:

search-package.png

编译执行

对于不同扩展名的文件,编译执行的方式是不同的,具体如下:
1、对于.js的文件:通过fs模块进行读取后,编译执行。
2、对于.node的文件:该模块是用c/c++模块编写的,需要用dlopen()方法进行加载,最后进行编译操作
3、对于.json的文件:用fs模块进行读取之后,用JSON.parse()方法进行解析。
4、其余扩展名的文件,都当成.js文件来处理。

每个模块编译成功之后,其文件路径会被缓存到Moudle._cache对象上,提高二次编译的速度。

js模块的编译

每个js模块都会进行一下步骤:
1、模块的包装

(function(exports, require, module, __filename, __dirname){
})

2、作用域的隔离
调用vm原生模块的runInThisContext()方法(好处是上下文明确,不污染全局)进行。

3、将方法返回给调用方法
最后将exports的属性和方法返回给外部调用。

node模块的编译

node调用process.dlopen()方法进行加载和执行,并不需要进行编译,因为是c/c++编写的,优势就是加载速度快。

json模块的编译

node调用fs模块读取文件,然后用JSON.parse()方法编译,导出给模块的exports对象。

js核心模块的编译

分为两步:1、转存到c/c++代码中。2、编译核心模块代码

1、采用自带的js2c.py工具,将代码转存到c/c++数组中,并且生成node_native.h头文件。当引入核心模块之后,根据标识符,将代码加载到内存中。
2、核心模块的编译过程,也经过包装(及作用域隔离),和普通模块的加载过程的区别(获取途径不同,核心模块是从内存中加载的。文件的缓存模块地址不同)

文件的缓存地址不同:核心模块会缓存到NativeModule._cache对象上,而普通模块会缓存到Module._cache对象上。而核心模块会通过process.binding('natives')方法取出

node模块的复合模式

node模块的复合模式:由c/c++来完成模块的内建,然后由js代码来完成向外的导出。该模式可以找到性能和开发速度之间的平衡点。

node内建模块的组织形式

module-organize.png

内建模块的导出及调用关系

callback-relation.png

module-export.png

核心模块引入实例

example-module.png

node模块之间的调用关系

module-callback.png