使用前初始化 RequireJS 模块

Initializing RequireJS modules before use

假设我有 3 个模块和 1 个主模块,如下所示:

//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 处理依赖关系的目的。我还不如只使用脚本标签并手动传递依赖项,确保每个脚本都是独立的。我很想知道是否还有其他解决方案。谢谢!

您可以在定义函数中进行模块初始化,并在 define([..] 中指定其依赖项:

//Module A
define(['SomeModule'], function(SomeModule){
  // initialization of the module

  return {
    //initializedModuleInterface..
  };
});

如果您遇到模块之间的循环依赖关系,那么您可以在模块的界面中 return 延迟第二个模块的需要,直到使用模块提供的功能,例如,通过不在 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 模块中使用 promises 作为内部依赖管理。

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

我们可以将模块主构造定义为一个承诺,并在我们有必要的数据时通过接口初始化函数解析它。

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