【问题标题】:Initializing RequireJS modules before use使用前初始化 RequireJS 模块
【发布时间】:2017-09-16 04:41:49
【问题描述】:

假设我有三个模块和一个主模块,如下所示:

//Module A
define([''], function(){
   function initialize(param1, param2){
      //initialize stuff
   }
   //other stuff

   return {
      initialize: initialize,
      //whatever else
   };
});

//Module B
define(['ModuleA'], function(ModuleA){
   function initialize(param2, param3){
      //initialize stuff using ModuleA
   }
   //other stuff

   return {
      initialize: initialize,
      //whatever else
   };
});

//Module C
define(['ModuleB'], function(ModuleB){
   function initialize(param4, param5){
      //initialize stuff using ModuleB
   }
   //other stuff

   return {
      initialize: initialize,
      //whatever else
   };
});

//main module
require(['ModuleA', 'ModuleB', 'ModuleC'], function(ModuleA, ModuleB, ModuleC){
   ModuleA.initialize(arg1, arg2);
   ModuleB.initialize(arg3, arg4);
   ModuleC.initialize(arg5, arg6);
});

这里的问题是主模块中的所有初始化调用之间存在时间耦合。作为程序员,我必须记住模块的初始化顺序。如果 ModuleB 在 ModuleA 之前初始化,那么它基本上将使用未初始化的模块,因为 ModuleA 尚未初始化。现在,我可以使用依赖注入,其中我实际上通过初始化方法中的参数传递 ModuleB 和 ModuleC 它们的依赖关系,但这会破坏 requirejs 处理依赖关系的目的。我还不如只使用脚本标签并手动传递依赖关系,确保每个脚本都是独立的。我很想知道是否有其他解决方案。谢谢!

【问题讨论】:

    标签: javascript dependency-injection module initialization requirejs


    【解决方案1】:

    您可以在define函数中进行模块初始化,并在define([..]中指定它的依赖关系:

    //Module A
    define(['SomeModule'], function(SomeModule){
      // initialization of the module
    
      return {
        //initializedModuleInterface..
      };
    });
    

    如果您偶然发现模块之间的循环依赖关系,那么您可以在从模块返回的接口中,推迟对第二个模块的需要,直到使用模块提供的功能,例如,通过要求它不在define([..] 但是当模块本身被使用时:require("a").doSomething();

    //Inside b.js:
    define(["require", "a"],
        function(require, a) {
            //"a" in this case will be null if "a" also asked for "b",
            //a circular dependency.
            return function(title) {
                return require("a").doSomething();
            }
        }
    );
    

    http://requirejs.org/docs/api.html#circular

    How to handle circular dependencies with RequireJS/AMD?

    初始化参数本身可以是另一个提供配置参数的模块。


    编辑 1:添加 requirejs 作为动态模块定义器和加载器的用法

    如果需要动态依赖注入机制的结构,你仍然可以使用requirejs。不确定它是否是为它设计的:

    1 .当你手头有必要的配置变量时,然后通过 requirejs 进行动态模块定义

    例如:

    angular.module('myModule')
    .run(function () {
      define('myConf', [], function() {
        return {
          confA: 1,
          confB: 2
        };
      });
    });
    

    2 。在依赖myConf 模块的模块中照常执行:

    // Module: ModuleA
    define(['myConf', function(myConf) {
      // initialization with myConf values.
      console.log(myConf.confA);
    
      return some_interface;
    });
    

    define(function(require) {
      var myConf = require('myConf');
      console.log(myConf.confA);
    
      // initialization with myConf values.
    
      return some_interface;
    });
    

    3 .在应用程序的生命周期中,当需要ModuleAModuleB.. 时:

    var moduleReq = 'moduleA';
    require([moduleReq], function (moduleA) {
      // doSomething with moduleA
    });
    

    这里的诀窍是dynamic defining of a module with a specific name 通过define('myConf', [], function() {..})。它使您无需文件即可在应用程序的生命周期内随时动态定义模块。据我了解,它主要用于 requirejs 捆绑解决方案。


    编辑 2:第二种方法 - 在 requirejs 模块中使用 Promise 作为内部依赖管理。

    可以使用的另一种方法是在 requirejs 模块中使用 Promise 来指定要等待的依赖项。

    我们可以将模块主构造定义为一个 Promise,并在我们拥有必要的数据时通过接口 init 函数解决它。

    1 .我们像往常一样将每个模块指定为系统中的一个文件。 2 .在我们想要动态初始化的confModule 中,我们以这种模式构建它:

    // confModule
    define([], function () {
       var resolveMain;
       var rejectMain;
    
       var promise = new Promise(resolve, reject) {
           resolveMain = resolve;
           rejectMain = reject;
       }
    
       return {
           init: function (confVarA, confVarB) {
               try {
                 var moduleInitialized = {
                   // some preparation of confModule
                   confVarA: confVarA,
                   confVarB: confVarB
                 };
                 resolve(moduleInitialized);
               } 
               catch (e) {
                  rejectMain(e);
               } 
           },
    
           then: function (successFn, errorFn) {
              return promise.then(successFn, errorFn);
           } 
       }
    });
    

    我们解决了outside of the constructor 的承诺。附加链接提供了有关该模式的好处和缺陷的更多信息。

    3 .在依赖模块中,我们以相同的模式定义它们,不需要 init 功能,并添加等待 confModule 的承诺:

    // moduleA
    define(['confModule'], function (confModule) {
       var resolveMain;
       var rejectMain;
    
       var promise = confModule.then(function(confModuleData) {
          var moduleBInterface = {
            // prepare module b 
          };
    
          return moduleBInterface; // this make the promise return another promise to wait on for moduleBInterface return;
       };
    
       return {
           then: function (successFn, errorFn) {
              return promise.then(successFn, errorFn);
           } 
       }
    });
    

    4 .在我们的代码中,当我们有我们需要的数据时,我们可以初始化 confModule:

    define(['confModule', function (confModule) {
       // some async get of confData
       $.get(url, function (data) {
         confModule.init(data.a, data.b);
       });
    });
    

    5.在我们的代码中,当使用 moduleA 时,我们需要将其用作一个 Promise:

    define(['moduleA'], fucntion (moduleA) {
      moduleA.then(function (moduleAInteface) {
        // do something with moduleA.
      });
    });
    

    【讨论】:

    • 我实际上已经考虑过了,但我需要初始化函数,因为我需要传入参数(在这种情况下来自主模块)。如果我以这种方式进行初始化,那么我将无法传递任何信息。不过感谢您的意见!
    • 我认为您正在尝试将 requirejs 用作手头有注入器的通用依赖注入机制。我已经更新了我的答案。不确定它是否用于使用:)
    • 但是将数据从主模块传递到其他模块以对其进行初始化似乎是一个常见问题。为什么 RequireJS 不适合这样做,那么这么多大型软件项目如何使用它呢?是否有另一种我不知道的构建他们使用的程序的方法?关于您的编辑,您是否在“第 1 步”中使用角度?
    • 1. Angular 只是我用来在应用程序生命周期中的某个时间初始化主配置模块的一个示例,而不是在我检查过的种子测试项目的开始时。您也可以在准备好 jquery 文档或在 ajax 调用之后执行此操作。 2.Not intended只是我的解释。只是在我以前的项目中没有看到这种用法。但这是一个干净有效的解决方案。
    • 3.这是一个常见的问题。您主要通过使用具有依赖注入机制的模块框架(例如 Angular)来解决它。但他们实际上在做同样的设计模式的事情。在代码中指定依赖项并等待它们。 stackoverflow.com/questions/16286605/…
    猜你喜欢
    • 2016-02-05
    • 2013-08-01
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 2018-02-13
    • 1970-01-01
    相关资源
    最近更新 更多