循环依赖 - Eloquent Javascript 书中的练习

问题描述 投票:0回答:1

我试图理解这段代码是如何工作的:(这是 Eloquent Javascript 书中的练习。http://eloquentjavascript.net/10_modules.html#i_E/zWqBFdy8

require.cache = Object.create(null);

function require(name) {
  if (!(name in require.cache)) {
    let code = readFile(name);
    let module = {exports: {}};
    require.cache[name] = module;
    let wrapper = Function("require, exports, module", code);
    wrapper(require, module.exports, module);
  }
  return require.cache[name].exports;
}

// Example:

// a.js
const {b} = require('./b');
console.log(b);
exports.a = 'a';

// b.js
const {a} = require('./a');
console.log(a);
exports.b = 'b';

书中指出:“许多模块系统只是禁止这种情况(循环依赖),因为无论您选择哪种顺序加载此类模块,都无法确保每个模块的依赖项在运行之前都已加载。”

解决方案是:“Require 在开始加载模块之前将模块添加到其缓存中。这样,如果在运行时进行的任何 require 调用尝试加载它,那么它已经是已知的,并且将返回当前接口,而不是再次开始加载模块。”

我无法理解模块加载顺序的含义 以及为什么我们不确定是否加载了依赖项,因为代码是同步的。最终我不确定我作为示例添加的两个模块中的代码如何交互。

javascript module
1个回答
0
投票

我正在读第四版。请求功能与您的稍有不同。为了完成这项工作,我们需要三个文件:

loader.js
a.js
b.js
。 Loader 包含
require
函数并加载所有模块。

它看起来像这样:

// loader.js
import {readFileSync} from 'fs';

function require(path) {
  if (!(path in require.cache)) {
    let code = readFileSync(path, 'utf8');
    let exports = require.cache[path] = {};
    let wrapper = Function("require, exports", code);
    wrapper(require, exports);
  }
  return require.cache[path];
}
require.cache = Object.create(null);

require('a.js');

// a.js
require('b.js');
console.log('finished loading a');

// b.js
require('a.js');
console.log('finished loading b');

当 A 被加载时,

require
函数首先将 A 添加到其缓存中。然后A模块需要B模块(此时A尚未完成加载)。当 B 开始加载时,它需要 A 模块,但 A 模块的
exports
已缓存,因此
require
函数从缓存中返回它 ({}) — 它不会再次加载。这个B加载完毕后,A模块中对
require
的调用返回,A就完成加载了。

注意当B需要A时,A还没有加载完成。因此,如果 A 在

require
调用之后导出某些函数,则该函数尚未可供 B 使用,访问它可能会导致问题。但是,如果 A 在需要 B 之前先导出一个值,则 B 将有权访问该值。同样,B 导出的所有内容始终可以被 A 访问,因为 B 总是先于 A 完成加载。

// a.js
exports.aLog = () => console.log('this is a logging!');
const {bLog} = require('b.js');
bLog();
console.log('finished loading a');

// b.js
const {aLog} = require('a.js');
aLog();
exports.bLog = () => console.log('this is b logging!');
console.log('finished loading b');

// → this is a logging!
// → finished loading b
// → this is b logging!
// → finished loading a
© www.soinside.com 2019 - 2024. All rights reserved.