marijnh / Eloquent-JavaScript

The sources for the Eloquent JavaScript book
https://eloquentjavascript.net
3.02k stars 796 forks source link

Stuck in Chapter 10 - Circular Dependencies #492

Closed alexpi closed 5 years ago

alexpi commented 5 years ago

Since this in not an issue with the book, feel free to ignore or point me to a relevant place (tried Stack Overflow, but got no answer) to ask my question.

I can't understand the hint on the last exercise of Chapter 10. http://eloquentjavascript.net/10_modules.html#i_E/zWqBFdy8

I made an example in order to understand:

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;
}

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

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

I am trying to trace the order of operations on the above:

  1. a requires b
  2. b requires a
  3. a requires b again, but now b is in cache, so require() returns require.cache[name].exports. This seems to return an empty object since the wrapper function hasn't arrived to the point of adding the exports value to the module.exports object.
  4. b.js continues on console.log(b) and outputs the empty object.

What am I getting wrong?

marijnh commented 5 years ago

You're not getting anything wrong—CommonJS circular dependencies are only filled in after the initial run of the module code. So if you have code like this instead....

const b = require("./b") // Note no curly braces
exports.test = function() { console.log(b.b) }

Calling test later on would work. But when the console.log in your code runs, the other module indeed hasn't initialized yet, so you can't use it. (And destructuring it like {b} doesn't work because when that statement is evaluated, the object is still empty, so the b you read is undefined.)