nodejs源碼中的require問題

提起nodejs中的模塊,就會想到用require去加在引用那個模塊。看了很多博客,加載機制明白了,腦子裏老是稀裏糊塗的知道會每一個文件會被'(function (exports, require, module, __filename, __dirname) {',
// 文件的源碼
'n});'包裹,天然也就有文件中的require命令了。前幾天看了模塊的源碼 https://github.com/nodejs/nod...
module.js源碼的前幾行node

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... 雖然還不是很明白,但獲得了一些思路,而後又開始從新看源碼,並動手調試,總算想清楚了。因而想寫寫記錄本身的整個過程。git

1、module.js前幾行的require從哪裏來的github

寫了兩個js文件,a.jsbootstrap

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

b.jsapp

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中能夠看到ui

const Module = NativeModule.require('module');也就是說會去加載module.js模塊。

在require函數中this

NativeModule.require = function(id) {
if (id === 'native_module') {
  return NativeModule;
}
/..../
const nativeModule = new NativeModule(id);新建NativeModule對象

nativeModule.cache();
nativeModule.compile();  //主要步驟

return nativeModule.exports;

};spa

在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,並不矛盾。

2、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...

相關文章
相關標籤/搜索