0
点赞
收藏
分享

微信扫一扫

node学习


content

  • ​​1. node的介绍​​
  • ​​2. 模块机制​​
  • ​​2.1 commonjs规范​​
  • ​​2.1.1 commenjs的模块规范​​
  • ​​2.2 node的模块实现​​
  • ​​2.2.1 路径分析​​
  • ​​2.2.2 文件定位​​
  • ​​2.2.3 模块编译​​
  • ​​核心模块​​

1. node的介绍

  • ​js缺陷​
  • 没有模块系统
  • 标准库少(文件系统,i/o等操作没有常见api)
  • 没有标准接口
  • 缺乏包管理工具
  • ​node特点​
  • ​异步I/O​​​ - 绝大多数的操作都以​​异步的方式​​进行调用

$.post('/url', {params}, function(data){
console.log('receive response')
})

  • ​事件与回调函数​
  • ​单线程​​ - 无法利用多核CPU
  • ​可以编写c/c++扩展方式​​提高CPU利用率

2. 模块机制

在js中没有向python(import), java(import)等语言的引入模块,为解决这些问题,引入了CommonJS规范。

2.1 commonjs规范

希望javascript能在任何地方运行。

  • ​出现的原因​​- 弥补当前js没有标准的缺陷。(没有模块系统,标准库少,没有标准接口,没有包管理系统)
  • ​web1.0​​ - js只有对dom和bom等基本操作。
  • ​web2.0​​ - h5的出现,进入web应用时代,有很多api让js调用。提高API供js调用

2.1.1 commenjs的模块规范

2.2 node的模块实现

模块的分类:

  • node提供的​​核心模块​
  • 核心模块包括HTTP,fs, path等
  • 部分源代码在编译中,编译为​​二进制执行文件​
  • 在node进行​​启动时​​​,部分核心模块,被​​加载内存中​
  • 对于这​​部分核心模块​​​,​​文件定位​​​和​​编译执行​​​被​​省略​​,在路径分析中有点判断,加载速度最快。
  • 用户编写的文件模块

​优先从缓存加载​​​ - node对引入过的模块会进行缓存,减少二次开销。​​node缓存的是编译和执行之后的对象。​

​引入模块的步骤​​:

  • 路径分析
  • 文件定位
  • 编译执行

2.2.1 路径分析

  • ​模块标识符​​分析,require()方法接受一个标示符作为参数。

const variable = require('模块标示符')

  • 核心模块 - 优先级仅次于缓存模块
  • 路径路径形式的文件模块 - . …和/的标示符
  • 自定义模块 - 非核心模块

console.log(module.paths); // 返回的是数组
// 生成路径的规则
* 当前目录下的node_modules目录
* 父目录下的node_modules目录
* 父目录的父目录下的node_modules目录
* 。。。 依次的地递归

2.2.2 文件定位

依据缓存加载的优先策略使得不需要路径分析、文件定位和编译执行的过程,大大提高再次加载模块时的效率。文件定位工作如下:

  • ​文件扩展名分析​​​ - require()分析过程中,会对不包含文件扩展名,​​node会按照.js , .json , .node次序补足扩展名​​。
  • ​目录分析和包​​ - 当在分析标示符没有查到文件时,首先,node在当前目录下查找package.json,通过JSON.parse解析出描述对象,从中抽取main的value,进行文件定位。若无package.json文件,则node按照index.js,index.json和index.node文件进行查找

...
"main": "index.js", //在package.json指定main
"module": "es/index.js",
"typings": "types/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/alibaba-fusion/next.git"
}
...

2.2.3 模块编译

node中,​​每个文件模块都是一个对象​​。

关于不同的文件的编译过程如下,查看源代码下,lib/module.js可知道:
​​​.js文件​​ - 通过fs模块,同步读取文件后编译执行

// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
var content = NativeModule.require('fs').readFileSync(filename, 'utf8');
module._compile(stripBOM(content), filename);
};

​.node.js文件​​ - 这是c/c++的扩展文件,通过dlopen方法加载最后编译生产的文件.

//Native extension for .node
Module._extensions['.node'] = process.dlopen;

​.json文件​​ - 通过fs模块,同步读取,用JSON.parse解析返回结果.

Module._extensions['.json'] = function(module, filename) {
var content = NativeModule.require('fs').readFileSync(filename, 'utf8');
try {
module.exports = JSON.parse(stripBOM(content));
} catch (err) {
err.message = filename + ': ' + err.message;
throw err;
}
};
//Module._extensions 会被赋值为require()的extension属性
// console.log(require.extensions)
// { '.js': [Function], '.json': [Function], '.node': [Function] }

​其余文件​​ - 当做js文件加载.

核心模块

分为c/c++编写和js编写:

​js编写​​ - 文件存放于lib目录下

  • 先转换为c/c++代码,使用v8附带的js2c.py工具,将所以js代码,转换为c++数组里.
  • 编译js核心代码,js核心模块通过process.binding(‘natives’)取出,编译成功的缓存模块存到NativeModule._cache对象上,文件模块则缓存在Module._cache对象上.

​c/c++编写​​ - 存在与node的src目录下

分为纯c/c++编写,称为​​内建模块​​。

部分c/c++编写,buffer,crypto,evals,fs,os等模块.

下面讲对​​内建模块进行说明​​:

​优点​​: 本身是由c/c++编写,性能上优于脚本语言,文件被编译成二进制文件,一般执行,就被加载到内存中,需要标识符定位,文件定位,编译等过程。

编写的内建模块,统一放进node_extensions.h文件中放进node_module_list数组中。
内建模块的依赖关系如下,不推荐直接通过node文件调用内建模块:

[外链图片转存失败(img-hFbE2IDn-1562430409356)(​​https://s2.ax1x.com/2019/06/22/ZpdXXd.png​​)]

核心模块os的流程:

  1. 先通过NOde_module对os的操作进行存储,这里我理解的是key:function(){}形式
  2. 再通过get_builtin_module(‘node_od’)形式调用
  3. process.binding(‘os’) 可以通过js调用reg_func函数
  4. 编译成功的模块缓存到NativeModule_cache对象上,再通过NativeModule.require(‘os’)调用
  5. 最后就可以在js中使用

[外链图片转存失败(img-1a7hBuGf-1562430409357)(​​https://s2.ax1x.com/2019/06/22/Zpwa4K.png​​)]


举报

相关推荐

0 条评论