MST

星途 面试题库

面试题:JavaScript模块中如何处理循环依赖

在JavaScript的模块化开发中,当出现循环依赖时可能会导致一些问题。请阐述循环依赖产生的场景,并说明ES6模块和CommonJS模块分别是如何处理循环依赖的,最好能举例说明。
25.0万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

循环依赖产生的场景

在模块化开发中,当模块A依赖模块B,同时模块B又依赖模块A时,就会产生循环依赖。例如:

  • 模块A:
// moduleA.js
import { bFunction } from './moduleB.js';
console.log('moduleA starting');
function aFunction() {
    console.log('aFunction');
    bFunction();
}
export { aFunction };
console.log('moduleA ending');
  • 模块B:
// moduleB.js
import { aFunction } from './moduleA.js';
console.log('moduleB starting');
function bFunction() {
    console.log('bFunction');
    aFunction();
}
export { bFunction };
console.log('moduleB ending');

如果在一个脚本中导入moduleA,就会触发循环依赖。

ES6模块处理循环依赖

ES6模块在遇到循环依赖时,会以“冻结”的状态处理。当一个模块被导入时,它会先创建该模块的实例,即使模块尚未完全执行完毕。这个实例的属性值在导入时都是undefined,直到模块执行完毕才会填充真实的值。 例如上面的例子,当执行导入moduleA时:

  1. 开始导入moduleA,创建moduleA的实例。
  2. moduleA中导入moduleB,创建moduleB的实例。
  3. moduleB中导入moduleA,由于moduleA的实例已存在,所以直接使用,此时moduleA实例的属性aFunctionundefined
  4. moduleB继续执行,定义bFunction,但由于aFunctionundefined,如果bFunction中调用aFunction会报错(在实际执行到bFunction调用aFunction时)。
  5. moduleB执行完毕,moduleA继续执行,定义aFunctionmoduleA执行完毕。

CommonJS模块处理循环依赖

CommonJS模块在遇到循环依赖时,会返回已经执行的部分。当一个模块被第一次加载时,它会开始执行,在执行过程中如果遇到对另一个模块的require,会暂停当前模块的执行,去加载并执行被依赖的模块。如果出现循环依赖,被依赖的模块会返回它已经执行的部分。 例如:

  • 模块A:
// moduleA.js
const moduleB = require('./moduleB.js');
console.log('moduleA starting');
function aFunction() {
    console.log('aFunction');
    moduleB.bFunction();
}
exports.aFunction = aFunction;
console.log('moduleA ending');
  • 模块B:
// moduleB.js
const moduleA = require('./moduleA.js');
console.log('moduleB starting');
function bFunction() {
    console.log('bFunction');
    // 如果在这里调用moduleA.aFunction会报错,因为此时aFunction还未定义
}
exports.bFunction = bFunction;
console.log('moduleB ending');

当执行require('moduleA')时:

  1. 开始加载moduleA,执行到require('./moduleB.js')
  2. 开始加载moduleB,执行到require('./moduleA.js'),由于moduleA正在加载中,所以返回moduleA已经执行的部分(此时aFunction还未定义)。
  3. moduleB继续执行,定义bFunctionmoduleB执行完毕。
  4. moduleA继续执行,定义aFunctionmoduleA执行完毕。