对NodeJS模块机制的理解

时间: 2019-10-30阅读: 32标签: 机制

1. CommonJS模块规范

1.1 模块引用


var math = require('math');

1.2 模块定义

上下文提供exports对象用于导出当前模块的方法和变量,并且他是唯一的导出出口,exports实际上是module.exports,而module.exports就是以一个暴露给外部的对象。

  • exports.some就是给这个对象上添加属性
  • 直接使用 module.exports = {...} 则可以让外部直接获取到这个对象,相当与为exports换了一个引用,如果在这之前使用exports.some会把之前的覆盖

1.3 CommonJS 用法

// a.js
module.exports = {
    a: 1
}
// or 
exports.a = 1

// b.js
var module = require('./a.js')
module.a // -> log 1

1.4 原理

var module = require('./a.js')
module.a 
// 这里其实就是包装了一层立即执行函数,这样就不会污染全局变量了,
// 重要的是 module 这里,module 是 Node 独有的一个变量
module.exports = {
    a: 1
}
// module 基本实现
var module = {
  id: 'xxxx', // 我总得知道怎么去找到他吧
  exports: {} // exports 就是个空对象
}
// 这个是为什么 exports 和 module.exports 用法相似的原因
var exports = module.exports 
var load = function (module) {
    // 导出的东西
    var a = 1
    module.exports = a
    return module.exports
};
// 然后当我 require 的时候去找到独特的
// id,然后将要使用的东西用立即执行函数包装下,over


2. Node的模块实现

在Node中引入模块,需要经历3个步骤

  • 路径分析
  • 文件定位
  • 编译执行
在node中,模块分为两类:一类是node提供的模块称为核心模块,一类是用户编写的成为文件模块。  
  • 核心模块在编译中编译成了二进制文件。在Node进程启动时,部分核心模块就被直接加载入内存。所以这部分核心模块引入时就省了文件定位和编译执行这两个步骤,并且在路径分析中优先判断,它的加载速度是最快的。

  • 文件模块是运行时动态加载。需要完整的路径分析、文件定位、编译执行

2.1 优先从缓存加载

Node对引入的模块都回进行缓存,而且缓存的是编译执行后的对象。  不管是核心模块还是文件模块,require()都一律采用缓存优先的方式。

2.2 路径分析和文件定位

2.2.1 模块标识符分析

  • 核心模块
  • 路径形式的文件模块
  • 自定义模块
    • node_modules下
    • 查找最费时

2.2.2 文件定位

  • 文件拓展名分析
    • 如果省略拓展名,回按 .js .node .json的次序依次尝试
    • 如果.node .json的话,加上拓展名会加快一点速度
    • 同步配合缓存,可大幅缓解单线程中阻塞式调用的缺陷
  • 目录分析和包
    • 如果没有文件名,会将Index当作默认文件名

2.3 模块编译

  • .js文件
    • 通过fs同步读取后编译执行
  • .node
    • 这是用C/C++编写的拓展文件,通过dlopen()方法加载最后编译生成的文件
  • .json
    • 用JSON.parse()解析返回结果
  • 其余拓展名
    • 当作.js文件处理
每一个编译成功的模块都会将其文件路径索引缓存在Module._cache对象上,以提高二次引入性能  

2.3.1 js模块的编译

在编译的过程中,Node对获取的JS文件进行了头尾包装。这也是每个模块都能访问到 require、exports、module、__filename、__dirname的原因  

(funciton(exports, require, module, __filename, __dirname) {
  
  /* 自己写的代码  */

});

这样使得模块文件间都进行了作用域隔离,不用担心变量污染全局。

为moudle.exports赋值,exports对象是通过形参的方式传入,直接赋值形参会改变形参的引用,但并不能改变作用域外的值。

exports = function() {
  // my class
}

var change = function(a) {
  a = 100;
}

var a = 10;
change(a);
console.log(a); // => 10

如果要达到require引入一个类的效果,请赋值给 module.exports对象。这个迂回的方案不改变形参的引用。

2.3.2 C/C++ 模块的编译

Node调用process.dlopen()方法进行加载和执行。

实际上 .node模块并不需要编译,因为它是编写C/C++模块之后编译生成的,所以这里只有加载和执行的过程。在执行的过程中,模块exports对象与.node模块产生练习,然后返回给调用者。


3. 核心模块

Node的核心模块在编译成可执行文件的过程中被编译进了二进制文件。核心模块其实分为C/C++编写的和Javascript编写的两部分,其中C/C++文件存放在Node项目的src目录下,Javascript文件存放在lib目录下。  

  1. C/C++拓展模块

  2. 模块调用栈

  3. 前后端公用模块

  4. 模块侧重点
  • 前端瓶颈在于带宽,后端瓶颈在于CPU和内存等资源。前端需要通过网络加载代码,后端则从磁盘加载,二者加载速度不再同一量级上。

  • node的模块引入几乎都是同步的,但前端模块若是也采用同步方式来引入必会在用户体验上造成很大的问题,即UI初始化实际过长


4. AMD规范

Asynchronous Moudle Definition “异步模块定义”, AMD需要在声明的时候指定所有的依赖,通过形参传递依赖到模块内容中。  

定义如下

define(id?, dependencies, factory);


5. CMD 规范

与AMD主要区别在于定于模块与依赖引入部分。  

CMD支持动态引入

define(funtion(require, exports, moudle) {
  // The module code goes here
})
作者: Web前端社区
出处:https://www.cnblogs.com/fecommunity/p/11922227.html


吐血推荐

1.站长广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入...

2.休闲娱乐: 网页游戏  直播/交友   H5游戏

链接: http://www.fly63.com/article/detial/6677

js执行机制

js是单线程的,为什么可以执行异步操作呢?这归结与浏览器(js的宿主环境)通过某种方式使得js具备了异步的属性。进程:正在运行中的应用程序。每个进程都自己独立的内存空间。例如:打开的浏览器就是一个进程。

Js事件循环(Event Loop)机制

Event Loop是计算机系统的一种运行机制,是个很重要的概念。而Javascript用这种机制来解决单线程运行带来的问题。理解很熟悉将会有利于我们更容易理解Vue的异步事件。Js是一种运行在网页的简单的脚本语言

Js之DOM事件机制

事件是在编程时系统内发生的动作或者发生的事情,系统会在事件出现的时候触发某种信号并且会提供一个自动加载某种动作的机制(来自MDN)。每个事件都有事件处理器(有时也叫事件监听器)

Node.js之模块机制

其实在JavaScript的发展中,它主要是在浏览器前端中被应用广泛。因为在实际应用中, JavaScript的表现能力主要取决于宿主环境的API支持程度, 在最早期,只有对BOM, DOM的支持,随着HTML5的出现,在浏览器中出现了更多

请介绍一下MySQL数据库的锁机制?

当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

JS事件循环机制

js是一门单线程的编程语言,也就是说js在处理任务的时候,所有任务只能在一个线程上排队被执行,那如果某一个任务耗时比较长呢?总不能等到它执行结束再去执行下一个。所以在线程之内

深入解析 Node.js 事件循环工作机制

本文从对线程、事件循环、事件循环常见的问题和错误上分别进行说明,进一步探索了 Node 的核心工作原理。每当人们谈论 Node.js 时,都会出现很多问题,比如它 究竟是什么 、这项技术有什么用、它是否 有未来 等等。

PHP中session机制解析

php默认用磁盘文件来实现session,在php.ini中session.save_handler = files定义session机制,sesson_start()函数是启动session的开始,session默认存放在文件中,且具有一定概率触发session的垃圾回收机制。

理解Redis的内存回收机制

Redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?笔者结合在工作上遇到的问题学习分析,希望看完这篇文章能对大家有所帮助。

Vue中的provide/inject机制

这对选项是一起使用的。以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

广告赞助文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全