【发布时间】:2016-09-30 16:10:49
【问题描述】:
我有一个 NodeJS 服务器应用程序,它被拆分为丢失的 ES6 模块。我正在尝试创建一种“加载模块处理程序”,主模块中的一个函数,其他模块需要注册一个回调,该回调将在主模块完全初始化后执行。我正在使用 Babel(使用 babel-preset-es2015)将 ES6 模块转换为可执行的 JavaScript。
为了简单地演示这里的问题,我创建了 2 个示例文件。
文件index.js(应用入口,主模块):
import * as js2 from "./js2.js";
let toCall = [], // this array handles callbacks from other modules
initialized = false; // flag
export function onInit (cb) { // registers cb to execute after this module is initialized
if (initialized) {
cb();
return;
}
toCall.push(cb);
}
function done () { // initialization is done - execute all registered callbacks
toCall.forEach(f => f());
}
// some important stuff here
// callback(() => {
initialized = true;
done();
// });
还有另一个模块js2.js:
import { onInit } from "./index";
onInit(() => {
console.log("Now I can use initialized application!");
});
对我来说一切似乎都很好,但不幸的是,在第一个文件中抛出下一个错误不起作用:
Cannot read property 'push' of undefined
问题是,此时没有toCall 变量,但为什么呢?变量toCall 被声明之前 onInit 函数,它必须准备好在onInit 中使用,不是吗?如何解决这个问题,我的方式是否足够合理以实现称为“模块初始化回调”的东西?有没有其他解决方案?
感谢您的任何帮助和建议。
【问题讨论】:
-
我在 babel/React 应用程序中遇到了类似的问题。模块在其导入之一之前加载,导致
undefined异常。 :( -
所以我的问题的解决方案是不运行顶级模块代码,仅在根入口点 JS 文件中运行。我将 Babel 与 CommonJS 一起使用,它根据导入依赖项处理模块加载,但浏览器仍然必须同步运行代码,这可能会导致加载顺序问题。我认为解决您的问题的一种方法是将模块代码放入 IIFE 中,该 IIFE 将在满足所有依赖项后运行。我希望这个评论是相关的。
-
布伦登,感谢您的提示。但是,我开始使用您提到的策略,因为我还没有找到我的问题的答案。当然,有了答案将使项目架构更加美观。可能是,这是一个 Babel 问题。查看生成的 ES5 代码,我可以猜到的解决方案是将
require(...)s 放在所有需要独立的变量声明之后。看看我这里的回答,我找到了正确的方法。 -
我看不出定义此类回调的意义。所有初始化都可以在没有循环依赖的情况下完成。
标签: javascript node.js ecmascript-6 node-modules