1. CommonJS模块规范

1.1 模块引用

var math = require('math');

1.2 模块定义

[!NOTE]

上下文提供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文件处理

[!NOTE]

每一个编译成功的模块都会将其文件路径索引缓存在Module._cache对象上,以提高二次引入性能

2.3.1 js模块的编译

[!NOTE]

在编译的过程中,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. 核心模块

[!NOTE]

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

【前端知识体系-NodeJS相关】对NodeJS模块机制的理解的更多相关文章

  1. 【前端知识体系-JS相关】ES6专题系列总结

    1.如何搭建ES6的webpack开发环境? 安装Node环境 node -v // 10.14.1 安装NPM环境 npm -v // 6.4.1 安装babel npm install @babe ...

  2. 【前端知识体系-CSS相关】CSS工程化方案

    1.如何解决CSS的模块化问题? 使用Less,Sass等CSS预处理器 使用PostCSS插件(postcss-import/precss) 使用webpack处理CSS(css-loader + ...

  3. 【前端知识体系-JS相关】对移动端和Hybrid开发的理解?

    1.hybrid是什么,为何使用hybrid呢? 概念: hybrid就是前端和客户端的混合开发 需要前端开发人员和客户端开发人员配合完成 某些环节也可能会涉及到server端 大前端:网页.APP. ...

  4. 【前端知识体系-JS相关】深入理解MVVM和VUE

    1. v-bind和v-model的区别? v-bind用来绑定数据和属性以及表达式,缩写为':' v-model使用在表单中,实现双向数据绑定的,在表单元素外使用不起作用 2. Vue 中三要素的是 ...

  5. 【前端知识体系-JS相关】JS基础知识总结

    1 变量类型和计算 1.1 值类型和引用类型的区别? 值类型:每个变量都会存储各自的值.不会相互影响 引用类型:不同变量的指针执行了同一个对象(数组,对象,函数) 1.2 typeof可以及检测的数据 ...

  6. 【前端知识体系-CSS相关】Bootstrap相关知识

    1.Bootstrap 的优缺点? 优点:CSS代码结构合理,现成的代码可以直接使用(响应式布局) 缺点:定制流程较为繁琐,体积大 2.如何实现响应式布局? 原理:通过media query设置不同分 ...

  7. 【前端知识体系-CSS相关】CSS预处理器

    1.常见的CSS预处理器有哪些? [!NOTE] css预处理器:用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行编码工作,可以让你的CS ...

  8. 【前端知识体系-JS相关】10分钟搞定JavaScript正则表达式高频考点

    1.正则表达式基础 1.1 创建正则表达式 1.1.1 使用一个正则表达式字面量 const regex = /^[a-zA-Z]+[0-9]*\W?_$/gi; 1.1.2 调用RegExp对象的构 ...

  9. 【前端知识体系-JS相关】深入理解JavaScript异步和单线程

    1. 为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Jav ...

  10. 【前端知识体系-JS相关】组件化和React

    1. 说一下使用jQuery和使用框架的区别? 数据和视图的分离,(jQuery数据和视图混在一起,代码耦合)-------开放封闭原则 以数据驱动视图(只关注数据变化,DOM操作被封装) 2.说一下 ...

随机推荐

  1. 爬虫(十):AJAX、爬取AJAX数据

    1. AJAX 1.1 什么是AJAX AJAX即“Asynchronous JavaScript And XML”(异步JavaScript和XML)可以使网页实现异步更新,就是不重新加载整个网页的 ...

  2. CODING 敏捷看板全新上线,助力研发管理可视化升级

    在服务企业研发团队的过程中,我们发现不少团队碰到了类似的问题: 团队成员声称完成了自己的大部分任务,但团队实际交付的需求却寥寥无几? 由于某些问题导致工序一直处于等待状态,怎么识别和处理这些延迟? 成 ...

  3. TopCoder12729 「SRM589Medium」GearsDiv1 二分图最小点覆盖

    问题描述 \(N\) 个齿轮每个齿轮有颜色(RGB),有些齿轮之间会咬合,你需要删除尽量少的齿轮并给每种颜色安排方向使得咬合齿轮不同向.问最多保留多少个齿轮.保证不存在两个相同颜色的齿轮咬合. sub ...

  4. jquery-获取button的值

    <button id="test" name="test_name" value="test_value"></butto ...

  5. Node.js / Python 日志

    一.Node.js 日志 1.原生 Node.js 原生方法其实很简单,就四个: // 输出到 stdout console.log() console.info() = console.log() ...

  6. CefSharp 无法输入中文的问题

    在CefSharp75版本,使用了WpfImeKeyboardHandler支持后,无法支持搜狗中文输入法 其中的一个修复方案: 在ChrominumWebBrowser中,添加焦点事件的重写,对In ...

  7. Dotnet Core中使用AutoMapper

    官网:http://automapper.org/ 文档:https://automapper.readthedocs.io/en/latest/index.html GitHub:https://g ...

  8. CSS入门(定位之浮动定位、伪类之鼠标悬停、光标修改和透明度修改和列表样式)

    一.定位 所为定位,实际上就是定义元素框相对于其正常位置,应该出现在哪儿 定位就是改变元素在页面上的默认位置 分类: 普通流定位(元素默认的定位方式) 浮动定位 相对定位 绝对定位 固定定位 1.普通 ...

  9. iOS开发中全量日志的获取

    我们在app中对崩溃.卡顿.内存问题进行监控.一旦监控到问题,我们就需要记录下来,但是,很多问题的定位仅靠问题发生的那一刹那记录的信息是不够的,我们需要记录app的全量日志来获取更多的信息. 一,使用 ...

  10. Violet音乐社区 - 个人总结报告

    一.项目概述 1.1 项目背景 音乐是一门艺术,是由有组织的乐音来表达人们情感.反映人类现实生活情感的艺术.现代科技的发展使得人们可以利用网络随时随地的享受音乐,然而在当今互联网却很少有一个以音乐为媒 ...