大多数人都知道Node.js中require()函数做什么的,但是有多少人知道它的工作原理呢?我们每天使用它加载库包和模块,但是它的内部行为原理很神秘。

  我们追寻Node模块系统的核心: module.js,这个文件包含一个令人惊讶的神奇功能,它负责加载 编译和缓存每个用过的文件,让我们揭开它的神秘面纱。

function Module(id, parent) {    this.id = id;    this.exports = {};    this.parent = parent; 
  // ... 

  在module.js中可以发现这个Module类型,扮演两个主要角色:首先,它提供一个所有Node.js模块从其文件被加载时构建一个实例的基础功能,甚至在文件运行时持久,这就是为什么我们能够将一些属性加入module.exports,并在需要时返回它们。

  module的第二个事情是处理Node模块的加载机制,标准的require函数其实是基于module.require的抽象,后者只是一个对Module._load的简单包装,加载方法处理每个文件的实际加载。看看它的代码大概如下:

Module._load = function(request, parent, isMain) { 
  // 1.在Module._cache中检查模块是否被缓存
  // 2.如果缓存中为空,创建一个新的模块实例。
  // 3. 保存到缓存
  // 4. 使用指定的名称调用module.load() 
  //    在读取了文件内容后将调用module.compile() 
  // 5.如果加载和分析文件时有错误
  //    从缓存中删除坏的模块
  // 6. 返回 module.exports 
}; 

  Module._load负责加载新的模块并且管理模块缓存,缓存每个模块能够降低文件的读取频率,从而提高性能,共享模块实例允许像单例模块那样跨应用保存状态。

  如果一个模块在缓存中不存在,Module._load将读取文件创建一个新的,读取文件内容成功后会调用module._compile

  如果你注意上面第六步,你会看到返回的是module.exports,这就是为什么当你定义公共接口时,可以使用exports和module.exports,因为它们确实是Model._load和require返回的。

  下面看看module._compile:

Module.prototype._compile = function(content, filename) { 
  // 1. 创建调用模块需要的require标准函数
  // 2.将其他帮助方法加入require. 
  // 3.包装JS代码到一个函数,这个函数提供我们的require
  //  模块, 比如变量本地化到模块的作用域
  // 4.返回这个函数
}; 

  这里有魔术发生,首先,一个特殊的标准require函数将被创建,这就是我们熟悉的require()函数,当函数自己包装了Module.require,它还包含一些很少人知道的帮助属性和方法,如:

  • require():加载一个外部模块
  • require.resolve(): 根据其绝对路径解决模块名称
  • require.main: 主要的模块
  • require.cache: 所有缓存模块
  • require.extensions: 基于文件的扩展名可用于编译的方法。

  一旦require准备就绪,整个源码将被包装进一个新的函数,这个函数有require module和exports和其他暴露变量作为参数,这创建了模块的一个新函数作用域,这样就不会污染Node.js环境的其余部分。

(function (exports, require, module, __filename, __dirname) { 
  // YOUR CODE INJECTED HERE! 你的代码在这里
}); 

  最后,这个包装了模块的函数将运行,整个Module._compile方法同步执行,这样原来对Module._load方法调用将会等待这个代码运行,然后才会完成,返回module.exports给用户。

 

Node.js的require()的工作原理的更多相关文章

  1. node.js使用require给flume提交请求

      node.js使用require给flume提交请求 - 简书 https://www.jianshu.com/p/02c20e2d011a     玄月府的小妖在debug 关注 2017.04 ...

  2. windows下搭建node.js及npm的工作环境

    近期在研究数据可视化D3框架,决定在windows下搭建一个nodejs及npm的工作环境,在网上查了n篇文章,别管是编译源代码安装也好.还是使用node.msi格式安装包也好,总是有问题.终于,功夫 ...

  3. [ 转]Node.js模块 require和 exports

    什么是模块? node.js通过实现CommonJS的Modules/1.0标准引入了模块(module)概念,模块是Node.js的基本组成部分.一个node.js文件就是一个模块,也就是说文件和模 ...

  4. NODE.JS exports require理解

    node.js exports 的作用是什么? 因为A.js文件想访问B.js文件中的类或函数,是不能直接访问的.为了解决这个问题 node.js 产生了 exports ,exports 实际可以理 ...

  5. node.js之require

    1.require.resolve('./testModeule.js')在REPL运行环境下输入,可以查询到当前目录下textModeule.js模块文件的完整文件名 2.require.cache ...

  6. 深入浅出,JS原型链的工作原理

    前言:原型链,即原型链条.它是由原型.原型的原型.原型的原型的原型...这一规则组合成的,经常被应用于继承. 原型的作用在JS中,每个对象都有自己的原型.当我们访问对象的属性和方法时,JS会先访问对象 ...

  7. 解析Vue.js中的computed工作原理

    我们通过实现一个简单版的和Vue中computed具有相同功能的函数来了解computed是如何工作的.写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指 ...

  8. Node.js模块 require和 exports

    https://liuzhichao.com/p/1669.html http://www.cnblogs.com/pigtail/archive/2013/01/14/2859555.html

  9. 深度理解Node.js单线程模型

    Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...

随机推荐

  1. 【luogu P2065 [TJOI2011]卡片】 假题解

    题目链接:https://www.luogu.org/problemnew/show/P2065 辣鸡匈牙利,没有优化贼鸡儿慢 // luogu-judger-enable-o2 #include & ...

  2. HDU 1175 连连看(超级经典的bfs之一)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1175 连连看 Time Limit: 20000/10000 MS (Java/Others)     ...

  3. HDU 1220 Cube(数学,找规律)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1220 Cube Time Limit: 2000/1000 MS (Java/Others)    M ...

  4. 我的wmware

    1.vmware 网络连接方式 NAT 模式: 虚拟机的IP 是由NAT分配的,电脑环境无论如何变化,都不会影响虚拟机 好处:在家.学校.公司,连接虚拟机都可以使用相同的ip地址 桥接模式: 只要更换 ...

  5. Page 由于代码已经过优化或者本机框架位于调用堆栈之上

    Page.Response.Clear();            Page.Response.Write("<script type=\"text/javascript\& ...

  6. 记录一次LOB损坏导致的EXPDP导出ORA-01555报错

    同事导出数据,结果遇到如下报错: expdp user1/XXXXXXXX directory=szdata1 dumpfile=szhzinfo_20180319.dmp logfile=szhzi ...

  7. iOS自动打开闪光灯

    现在好多应有都具备扫码功能,为了减少用户操作,一般会在光线比较暗的时候,自动打开闪光灯: 1.导入头文件 #import <AVFoundation/AVFoundation.h> #im ...

  8. js数组去重方法整理

    1.思路:定义一个新数组,并存放原数组的第一个元素,然后将原数组的项和新数组的元素一一对比,若不同则存放在新数组中. function unique(arr){ var res = [arr[0]]; ...

  9. JS数组去重的十种方法(转载)

    重点:博客原文出自http://www.cnblogs.com/yuanbo88/p/7345331.html.我只是想给自己做个笔记.感谢敲代码的怪蜀黍做的贡献. Methods 1: 思路:定义一 ...

  10. 【CodeForces 803 C】Maximal GCD(GCD+思维)

    You are given positive integer number n. You should create such strictly increasingsequence of k pos ...