node.js 中的 require() 是如何工作的?
Posted
技术标签:
【中文标题】node.js 中的 require() 是如何工作的?【英文标题】:How does require() in node.js work? 【发布时间】:2012-03-17 13:29:07 【问题描述】:我试过了:
// mod.js
var a = 1;
this.b = 2;
exports.c = 3;
// test.js
var mod = require('./mod.js');
console.log(mod.a); // undefined
console.log(mod.b); // 2
console.log(mod.c); // 3, so this === exports?
所以我认为 require() 可能是这样实现的:
var require = function (file)
var exports = ;
var run = function (file)
// include "file" here and run
;
run.apply(exports, [file]);
return exports;
对吗?请帮助我理解 require(),或者我在哪里可以找到源代码。谢谢!
【问题讨论】:
【参考方案1】:源代码为here。 exports
/require
不是关键字,而是全局变量。您的主脚本是 wrapped 之前的 start 在一个函数中,该函数在其上下文中包含所有全局变量,如 require
、process
等。
请注意,虽然 module.js 本身使用的是 require()
,但这是一个不同的 require 函数,它在名为“node.js”的文件中是 defined
上面的副作用:在模块中间有“return”语句(不属于任何函数)是非常好的,有效地“注释掉”其余代码
【讨论】:
这并没有让它变得更简单。该模块使用require
,同时还定义了require
。仅考虑到源代码,我觉得这一步有点难以理解。
模块本身需要一个不同的require。创建模块的简化版本来引导模块系统 - 看看这里的代码 - github.com/nodejs/node/blob/v4.0.0/src/node.js#L861-L949
这些全局变量及其返回值的文档在哪里?
@Srikan 在官方文档中 - nodejs.org/dist/latest-v8.x/docs/api/… (我对调用导出/需要全局变量并不完全正确 - 通常它们是加载模块时调用的包装函数的参数)
@AlexanderMills 它不完全是全局变量,这是因为每个模块都包装在一个函数中,require
作为参数之一传递给该函数【参考方案2】:
var mod = require('./mod.js');
require 是一个函数,它接受一个名为 path 的参数,在这种情况下,路径是 ./mod.js
当调用 require 时,会发生一系列任务:
调用lib/module.js 中声明的Module.prototype.require
函数,该函数断言路径存在并且是一个字符串
调用Module._load
,这是lib/module.js中的一个函数,通过Module._resolveFilename(request, parent, isMain)
解析文件,
Module._resolveFilename
函数并检查模块是否是本地的(本地模块由NativeModule
在lib/internal/bootstrap_node.js中定义的函数返回),
如果是,它将返回模块,否则它会检查 parh 的字符数(至少必须 2 个字符)和一些字符(路径必须以 ./
开头)
通过在lib/internal/bootstrap_node.js 中定义的Module._resolveLookupPaths
函数
检查包含文件的目录
如果路径包含扩展名(在我们的示例中是:mod.js),lib/path.js 中定义的基本名称函数会检查扩展名是否为“js”
然后它将为参数var module = new Module(filename, parent);
中给出的文件创建一个新模块
内容将通过lib/internal/bootstrap_node.js中定义的函数NativeModule.prototype.compile
通过v8编译
在lib/internal/bootstrap_node.js 中定义的NativeModule.wrap
采用mod.js
编译的javascript 内容并将其包装:它将其包装在其他代码中,使所有这些工作。
因此,您在mod.js
中编写的代码被包装在一个函数表达式中。这意味着您在 node 中编写的所有内容都在 V8 中运行
返回的是 module.exports
【讨论】:
【参考方案3】:Andrey 展示了源代码,但如果您也想知道如何使用它,这里有简单明了的解释(http://nodejs.org/api/modules.html)。
这对我来说是两个很好的例子。
//foo.js, multiple methods
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is ' + circle.area(4));
//circle.js
var PI = Math.PI;
exports.area = function (r)
return PI * r * r;
;
exports.circumference = function (r)
return 2 * PI * r;
;
//bar.js
var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());
//square.js, single method
module.exports = function(width)
return
area: function()
return width * width;
;
我最喜欢的模式是
(function (controller)
controller.init = function (app)
app.get("/", function (req, res)
res.render("index", );
);
;
)(module.exports);
【讨论】:
如果定义一个var express = require('express')
,为什么在它之后,他们必须重新定义另一个变量为var app = express()
?
不明白你最喜欢的模式与require有什么关系
@TomSawyer,因为require('express')
返回一个返回应用程序的函数。这只是他们建造它的方式。希望自从您 4 年前提出这个问题以来,您已经回答了它。【参考方案4】:
我挖掘了一点nodejs源代码/2/并制作了一个序列图/1/,希望这能给你一个直观的概述。还有一篇文章http://fredkschott.com/post/2014/06/require-and-the-module-system/也简单的解释了require()机制,先看这篇文章可以帮助你快速理解这个图。
参考:
/1/ 图源repo:https://github.com/z1yuan/nodejs.git
/2/https://github.com/nodejs/node-v0.x-archive.git
【讨论】:
【参考方案5】:试试这个。 这是我用来创建与 Node.js 相同功能的 sn-p
/*
FILE: require.js
*/
/*
This is the file used
*/
window.require = function(src, ret)
if (src === 'jsmediatags')
src = 'https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.5/jsmediatags.js';
;
var d = document.createElement('script');
d.src = src;
document.head.appendChild(d);
var fullURL = src.split('://');
var neededURL = fullURL[1];
var nameParts = neededURL.split('/');
var nameNUM = nameParts.length - 1;
var fileName = nameParts[nameNUM];
var g = fileName.split('.');
var global = g[0];
if (ret === true)
return window[global]
;
;
看看这是否有效,并将更多文件添加到其库中,只需输入更多。 (if (src===yourfilenamehere) src = "path/to/your/file"
【讨论】:
这没有回答 OP 的要求。 OP 询问require
功能如何工作以及如何实现。这个解决方案是如何用纯JavaScript重新创建node.js
require
函数。【参考方案6】:
在下载旁边可以找到源代码:http://nodejs.org/exports/require 是关键字,我不认为它们是直接用 javascript 编码的。 Node 是用 C++ 编写的,而 javascript 只是一个围绕 C++ 核心的脚本外壳。
【讨论】:
当您只是“思考”或猜测时,最好不要回答问题。当一个模块从文件系统加载和解析时,它被包装在一个函数中,并由 v8 引擎编译,最后模块被缓存。require
、module
、__filename
等是编译后注入模块的函数和变量,模块运行在v8引擎上下文中,但是模块本身是一个闭包,所以变量和函数永远不会冲突(除非你使用全局变量和混乱。以上是关于node.js 中的 require() 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章
node.js 中的 module.parent 有啥用?如何引用 require()ing 模块?
Node.js:如何将全局变量传递到通过 require() 插入的文件中?
Node.js 'require' 语句中的大括号(大括号)