摘要:提起中的模块,就会想到用去加在引用那个模块。看了不少博客,加载机制明白了,脑子里总是稀里糊涂的知道会每个文件会被文件的源码包裹,自然也就有文件中的命令了。于是想写写记录自己的整个过程。这就是几个的关系。
提起nodejs中的模块,就会想到用require去加在引用那个模块。看了不少博客,加载机制明白了,脑子里总是稀里糊涂的知道会每个文件会被"(function (exports, require, module, __filename, __dirname) {",
// 文件的源码
"n});"包裹,自然也就有文件中的require命令了。前几天看了模块的源码 https://github.com/nodejs/nod...
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去引用其他模块,从而陷入死循环。在一些技术网站提问https://cnodejs.org/topic/58b... 虽然还不是很明白,但得到了一些思路,然后又开始重新看源码,并动手调试,总算想清楚了。于是想写写记录自己的整个过程。
一、module.js前几行的require从哪里来的
写了两个js文件,a.js
</>复制代码
const b = require("./b.js");
b.js
</>复制代码
exports.done = false;
node 执行a.js
首先node启动时会先执行第一个js文件https://github.com/nodejs/nod...
这个文件中会定义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) { ",
"
});"
];
这里的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 program
process._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的关系。
新人第一次写,如有错误,还请纠正。
参考:
https://github.com/nodejs/nod...
https://github.com/nodejs/nod...
https://github.com/nodejs/nod...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/81946.html
摘要:先把当成文件,依次查找当前目录下的,找到了,就返回该文件,不再继续执行。那么关于正确的结论是在中使用是跟的效果相同,不会因为启动脚本的目录不一样而改变,在其他情况下跟效果相同,是相对于启动脚本所在目录的路径。 起因 原文收录在我的 GitHub博客 (https://github.com/jawil/blog) ,喜欢的可以关注最新动态,大家一起多交流学习,共同进步,以学习者的身份写博...
摘要:先把当成文件,依次查找当前目录下的,找到了,就返回该文件,不再继续执行。那么关于正确的结论是在中使用是跟的效果相同,不会因为启动脚本的目录不一样而改变,在其他情况下跟效果相同,是相对于启动脚本所在目录的路径。 起因 原文收录在我的 GitHub博客 (https://github.com/jawil/blog) ,喜欢的可以关注最新动态,大家一起多交流学习,共同进步,以学习者的身份写博...
摘要:之后需要对中的结果数据做分析,并且制作图表写周报发给老大。轮到我值班的时候就用写了一个脚本自动处理中的数据,并且将数据再写入文件。脚本目的读取文件,分析中的数据,并且将结果写入中。 背景 因为 Team 本身工作性质的问题,平时需要值班。值班数据可以导出为本地的Excel文件。之后需要对Excel中的结果数据做分析,并且制作图表写周报发给老大。 对于我这种对word都玩不转的人,别说用...
摘要:以异步方式事件队列为标准,基本每一套与网络相关的都会设计成异步的。在这种情况下,同步的网络请求比异步的请求会更加合适,代码更加清晰,逻辑更简单,而且对代码效率要求不高。如下,便是简化后的同步请求,文本替换的代码。 node.js 以异步方式、事件队列为标准,基本每一套与网络、IO 相关的 API 都会设计成异步的。 如,一段很平常的请求代码,用 node.js 只能用异步方式。 con...
阅读 1964·2021-11-22 15:24
阅读 1439·2021-11-12 10:36
阅读 3302·2021-09-28 09:36
阅读 1972·2021-09-02 15:15
阅读 2845·2019-08-30 15:54
阅读 2452·2019-08-30 11:02
阅读 2476·2019-08-29 13:52
阅读 3656·2019-08-26 11:53