博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nodejs源码中的require问题
阅读量:6972 次
发布时间:2019-06-27

本文共 3066 字,大约阅读时间需要 10 分钟。

提起nodejs中的模块,就会想到用require去加在引用那个模块。看了不少博客,加载机制明白了,脑子里总是稀里糊涂的知道会每个文件会被'(function (exports, require, module, __filename, __dirname) {',

// 文件的源码
'n});'包裹,自然也就有文件中的require命令了。前几天看了模块的源码
module.js源码的前几行

const NativeModule = require('native_module');const util = require('util');const internalModule = require('internal/module');const vm = require('vm');const assert = require('assert').ok;const fs = require('fs');const internalFS = require('internal/fs');

一上来就懵了,module.js不就是为了实现require的吗?为什么一上来就用require去引用其他模块,从而陷入死循环。在一些技术网站提问 虽然还不是很明白,但得到了一些思路,然后又开始重新看源码,并动手调试,总算想清楚了。于是想写写记录自己的整个过程。

一、module.js前几行的require从哪里来的

写了两个js文件,a.js

const b = require('./b.js');

b.js

exports.done = false;

node 执行a.js

首先node启动时会先执行第一个js文件
这个文件中会定义module.js中第一行的NativeModule。可以看到NativeModule的定义

function NativeModule(id) {this.filename = `${id}.js`;this.id = id;this.exports = {};this.loaded = false;this.loading = false;

}

从入口函数startup中可以看到

const Module = NativeModule.require('module');也就是说会去加载module.js模块。

在require函数中

NativeModule.require = function(id) {if (id === 'native_module') {  return NativeModule;}/..../const nativeModule = new NativeModule(id);新建NativeModule对象nativeModule.cache();nativeModule.compile();  //主要步骤return nativeModule.exports;

};

在compile中

NativeModule.prototype.compile = function() {var source = NativeModule.getSource(this.id);source = NativeModule.wrap(source);   this.loading = true;try {  const fn = runInThisContext(source, {    filename: this.filename,    lineOffset: 0,    displayErrors: true  });  fn(this.exports, NativeModule.require, this, this.filename);  this.loaded = true;} finally {  this.loading = false;}

};

wrap会进行文件的包裹

NativeModule.wrap = function(script) {return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];};NativeModule.wrapper = ['(function (exports, require, module, __filename, __dirname) { ','\n});'];

这里的require是NativeModule.require

接下来就会执行Module.runMain函数,从而进入module.js中,所以module

.js中开始的require是NativeModule.require,并不矛盾。

二、a.js的执行情况

执行a.js时则会通过bootstrap_node.js的runMain函数进入module.js

Module.runMain = function() {// Load the main module--the command line argument.Module._load(process.argv[1], null, true);// Handle any nextTicks added in the first tick of the programprocess._tickCallback();};调用Module._load函数,process.argv[1]为a.js

图片描述

Module.runMain->Module._load->tryModuleLoad->module.load->Module._extensions['.js']->module._compile

在module._compile中

var wrapper = Module.wrap(content);这个时候才调用NativeModule的wrap函数对a.js就行包裹

接下来

var require = internalModule.makeRequireFunction.call(this);会通过 https://github.com/nodejs/node/blob/master/lib/internal/module.js中的makeRequireFunction函数创造一个require函数,  function require(path) {  try {  exports.requireDepth += 1;  return self.require(path);} finally {  exports.requireDepth -= 1;}

}

call.(this)将指针指向module,从而a.js包裹的头部中require就是makeRequireFunction返回的require,
self.require(path);则会调用用Module.prototype.require

Module.prototype.require = function(path) {return Module._load(path, this, /* isMain */ false);};require则会调用 Module._load去加载其他模块。

这就是几个require的关系。

新人第一次写,如有错误,还请纠正。

参考:

转载地址:http://zfosl.baihongyu.com/

你可能感兴趣的文章
如何为crontab调度运行的多脚本设置共享的环境变量?
查看>>
bash字符串匹配
查看>>
选择设置好ext3日志模式
查看>>
程序员专用经典语录
查看>>
网络爬虫
查看>>
iOS开发基础
查看>>
5 创建型模式-----原型模式
查看>>
C++:vector中的resize()函数 VS reserve()函数
查看>>
JS对象和数组
查看>>
CodeForces - 1105C (dp)
查看>>
安装服务windows,installutil
查看>>
斐波那契数列
查看>>
如何在android程序中使用百度api接口:
查看>>
一位10年Java工作经验的架构师聊Java和工作经验
查看>>
英文词频统计预备,组合数据类型练习
查看>>
完成个人中心—导航标签
查看>>
UVA10603 Fill
查看>>
POJ NOI MATH-7652 乘积最大的拆分
查看>>
汉若塔问题算法程序
查看>>
解决Mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'问题
查看>>