node学习

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)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值