【问题标题】:JavaScript ES6 Module OnLoad handler implementationJavaScript ES6 模块 OnLoad 处理程序实现
【发布时间】: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


【解决方案1】:

我为此找到了一个漂亮的实现。

需要将“onload handler”实现分离到单个模块。作为这个示例的结果,将有三个文件:

index.js:

import * as js2 from "./js2.js";
import { initDone } from "./init.js";

// some important stuff here
// callback(() => {
    console.log(`Main module is initialized!`);
    initDone();
// });

js2.js:

import { onInit } from "./init.js";

onInit(() => {
    console.log("Module js2.js is initialized!");
});

init.js:

let toCall = [], // this array has to handle functions from other modules
    initialized = false; // init flag

export function onInit (cb) {
    if (initialized) {
        cb();
        return;
    }
    toCall.push(cb);
}

export function initDone () {
    initialized = true;
    toCall.forEach(f => f());
}

结果:

Main module is initialized!
Module js2.js is initialized!

【讨论】:

    猜你喜欢
    • 2011-07-22
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 2014-04-12
    • 2011-09-20
    相关资源
    最近更新 更多