概述nodejs模块系统核心原理

  • 核心工作原理
    • 模块解析过程(Module Resolve)
    • 模块对象(Module Object)
    • 模块包装(Module Wrapper)
    • 缓存(Cache)
    • 循环引用(Cycle)

核心工作原理

模块解析过程(Module Resolve)

test.js

require('x')
复制代码
  1. x是node核心模块(如http,zlib等)则返回,否则继续
  2. 根据Module对象的paths属性一直递归找node_modules文件夹下是否存在该模块,直到根目录,否则抛出Error('MODULE_NOT_FOUND')
  3. x是路径(如/path/to/file)
    • 尝试LOAD_AS_FILE(如.js,.json,.node),没有则继续
    • 尝试LOAD_AS_DIR(如文件夹下package.json),没有则抛出Error('MODULE_NOT_FOUND')

LOAD_AS_FILE:

  1. .js
  2. .json
  3. .node文件(编译好的二进制node插件)

LOAD_AS_DIR:

  1. X/package.json中的main字段作为模块入口文件
  2. index.js
  3. index.json
  4. index.node

模块对象

Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/Users/wl/Sites/myapp/node-learning/src/module/index.js',
  loaded: false,
  children:
   [
	   Module
	   {
		   id: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
		   exports: [Object],
		   parent: [Circular],
		   filename: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
		   loaded: true,
		   children: [Array],
		   paths: [Array]
		}
	],
  paths:
   [
		'/Users/wl/Sites/myapp/node-learning/src/module/node_modules',
		 '/Users/wl/Sites/myapp/node-learning/src/node_modules',
		 '/Users/wl/Sites/myapp/node-learning/node_modules',
		 '/Users/wl/Sites/myapp/node_modules',
		 '/Users/wl/Sites/node_modules',
		 '/Users/wl/node_modules',
		 '/Users/node_modules',
		 '/node_modules'
   ]
}
复制代码
  • id 模块id。通常为模块文件绝对路径,主模块通常为.
  • exports 模块导出对象。这里的exports指的是module.exports
  • parent 父模块。即被依赖模块
  • filename 模块文件名。通常与id相同
  • loaded 模块加载状态。是否已执行完成
  • children 子模块。即依赖模块
  • paths 模块查找路径数组。

模块包装(Module Wrapper)

主要由以下两点考虑

  • 使模块内定义的顶层变量限制在方法(也就是wrapper或者说模块内部)级作用域中,防止污染global环境

注:建议启用'use strict'模式,防止定义全局变量

  • 传入module, require有利于实现node模块化机制
(function(exports, require, module, __filename, __dirname) {
	// Module code
});
复制代码

缓存(Cache)

在一个node上下文环境中,两次require同一个文件,通常情况下返回完全相同的两个对象引用。除非用高阶函数返回工厂函数。

循环引用(Cycle)

由于node包相互依赖,则较大可能会形成循环引用,node利用其缓存机制避免无限循环。比如

index.js

const prefix = '主模块:'
const a = require('./a.js')

console.log(prefix, a)  // {a:2}
console.log(prefix, require.main === module)
console.log(module)
复制代码

a.js

'use strict'
const prefix = 'A模块:'
module.exports = {a:1}
const b = require('./b.js')
console.log(prefix, b)  // {b:1}
module.exports = {a:2}
console.log(prefix, require.main === module)
复制代码

b.js

const prefix = 'b模块:'
module.exports = {b:1}
const a = require('./a.js')
console.log(prefix, a) // {a:1}
console.log(prefix, require.main === module)
复制代码

如上。当b.js引用a.js时,为避免无限循环,a.js未完成的副本(我认为是require('./b.js')之前的所有代码,但是在官方文档中未得到特别确切的表述)导出的对象被b.js引用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值