在不同的amd模块之间共享资源

时间:2012-01-12 21:01:13

标签: backbone.js requirejs

我目前正在开发一个新的网络应用程序。

这是我第一次使用带有AMD模块的requirejs。

习惯那种新的范例并不容易 - 据我所知 - 全局命名空间中没有变量。

在以前的Web应用程序中,我总是在全局命名空间中有一个变量,我可以使用它来跨不同模块共享多个资源。

现在使用requirejs AMD模块,我使用backbone.js和jquery(两个amd版本 - jquery 1.7.1和backbone.js 0.5.3-optamd3)。

在我的应用程序的某处,我从服务器(用户对象)获取backbone.js模块。我想从不同的AMD模块访问该模块。我还想要一个应用程序范围的事件对象。

你能否告诉我:requirejs AMD在不同模块之间共享资源的正确方法是什么?

5 个答案:

答案 0 :(得分:31)

我自己找到了解决方案。

谢谢你,IntoTheVoid,你的答案,但我希望有类似AMD的解决方案。这意味着,不再是,"污染"全局命名空间。

我的解决方案有两个关键:

" https://github.com/addyosmani/backbone-aura"来自Addy Osmani和" https://github.com/amdjs/amdjs-api/wiki/AMD"异步模块定义(AMD)API规范。

规范说:"如果工厂是一个功能,它应该只执行一次。"

因此,如果在Web应用程序中多次指定amd模块作为依赖项,则依赖项不仅 NOT LOADED MULTIPLE TIMES ,它还 NOT EXECUTED MULTIPLE TIMES ,这对我来说是新事物。它只执行一次,并保留工厂功能的返回值。具有相同路径的每个依赖项具有相同的对象。这会改变一切。

因此,您只需定义以下amd模块:

define([], function() {
    var app_registry = {};
    app_registry.global_event_obj = _.extend({}, Backbone.Events);
    app_registry.models = {};
    return app_registry;
});

现在,在您想要共享资源的那些模块中,您将此app_registry模块声明为依赖项并写入一个:

define(['jquery','underscore','backbone','app_registry'], 
  function ($, _, Backbone, app_registry){
    var firstView = Backbone.View.extend({
    initialize: function() {
        _.bindAll (this, 'methodOne'); 
        this.model.bind ('change', this.methodOne);   
        this.model.fetch();
    },  
    methodOne: function() {
        app_registry.models.abc = this.model;
    }
    ...

和另一个:

define(['jquery','underscore','backbone','app_registry'], 
  function ($, _, Backbone, app_registry){
    var secondView = Backbone.View.extend({
    initialize: function() {
       _.bindAll (this, 'methodTwo'); 
        app_registry.global_event_obj.bind ('special', this.methodTwo);
    },  
    methodTwo: function() {
        app_registry. ...
    }
    ...

答案 1 :(得分:1)

要回答关于如何提供应用程序范围事件对象的问题,可以创建一个名为globalContext的amd模块并在main.js中实例化它。 此后,您可以将设置附加到globalContext,并使用全局上下文创建子组件等。

    //main.js file
    require([ "./global-context" ], function( GlobalContext) {
             new GlobalContext();
    });

在global-context.js文件中,我们可以执行诸如加载子模块之类的任务

    define(["Boiler", "./settings", "./modules/modules"], 
           function (Boiler, settings, modules) {
                  var GlobalContext = function () {

                //here we use a template javascript class called Boiler.Context
                var globalContext = new Boiler.Context("GlobalModule");

                //add settings to the context which can be obtained globally throughout                    the application
                globalContext.addSettings(settings);

                //here we load the sub modules of the global context
                globalContext.loadChildModules(modules);
};

这是我们在BoilerplateJS中实现的,这是一个用于大规模javascript产品开发的参考架构。

答案 2 :(得分:1)

您可以使用初始化模式将任何值注入requirejs模块(也称为“依赖注入”)。

在您的代码中的任何位置执行require调用:

var MyBackboneModule;

MyBackboneModule = someWayToGetAReferenceToIt();

require("module", function(Module) { 
  Module.initialize(MyBackboneModule);
});

将module.js文件定义为

define([], function(){
   var BackboneModuleDoingThisAndThat;

   function initialize(pBackboneModule) {
      BackboneModuleDoingThisAndThat = pBackboneModule ;
   };

   function doSomething() {
      var x = BackboneModuleDoingThisAndThat.computeThis(42);
   };


   return { 
      initialize: initialize
   };
});

答案 3 :(得分:0)

您可以在入口点AMD模块中定义单个全局APPAPP可以创建并保留对其他共享模块的引用:

APP = {
    this.settings : function() {
        if(settingsModule == undefined){
            //require, create and return it
        } else {
            return settingsModule;
        }
    }
}

答案 4 :(得分:-1)

只是评论你自己的答案 - 你不需要在你的app_registry模块中定义一个函数:

define({
  global_event_obj: _.extend({}, Backbone.Events);
  models: {}
});

应该足够了。

请参阅:the docs

但要小心这些事情。共享数据模块有用的用例。但是如果你最终将它用作伪全局命名空间,那么它只比使用全局变量更好(不是说你正在做的事情)。