跨不同 amd 模块共享资源

发布于 2024-12-26 10:12:16 字数 440 浏览 0 评论 0 原文

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

这是我第一次将 requirejs 与 AMD 模块一起使用。

据我了解,适应新的范例并不容易 -全局命名空间中没有变量。

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

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

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

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

I'm currently developing a new web application.

This is the first time I'm using requirejs with AMD modules.

It's not that easy to get used to that new paradigm that there are - as I understand it - no variables in the global namespace.

In previous web applications I always had one variable in the global namespace which I could use to share several resources across different modules.

Now with requirejs AMD modules, I use backbone.js and jquery (both amd versions - jquery 1.7.1 and backbone.js 0.5.3-optamd3).

Somewhere in my application I fetch a backbone.js module from the server (user object). I would like to have access to this module from different AMD modules. I also want to have an application wide event object.

Could you tell me: what is the right way in requirejs AMD to share resources across different modules?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

与风相奔跑 2025-01-02 10:12:16

我自己找到了解决方案。

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

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

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

规范说:“如果工厂是一个函数,它应该只执行一次。”

因此,如果在 Web 应用程序中多次将 amd 模块指定为依赖项,则该依赖项不仅不会多次加载,而且不会多次执行,这对我来说是新事物。它只执行一次,并保留工厂函数的返回值。具有相同路径的每个依赖项都具有相同的对象。这改变了一切。

因此,您只需定义以下 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. ...
    }
    ...

I found a solution myself.

Thank you, IntoTheVoid, for your answer, but I was hoping for an AMD-like solution. This means, not again, "polluting" the global namespace.

There were 2 keys to my solution:

"https://github.com/addyosmani/backbone-aura" from Addy Osmani and "https://github.com/amdjs/amdjs-api/wiki/AMD" the The Asynchronous Module Definition (AMD) API specification.

The spec says: "If the factory is a function it should only be executed once."

So, if an amd module is specified multiple times as a dependency in an web application, the dependency is not only NOT LOADED MULTIPLE TIMES, it is also NOT EXECUTED MULTIPLE TIMES, and this is the new thing to me. It is only executed once and the return value of the factory function is kept. Each dependency with the same path has the same object. And this changes everything.

So, you simply define the following amd module:

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

Now, in those modules where you want to share resources, you declare this app_registry module as dependency and write in one:

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

and in the other:

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. ...
    }
    ...
情魔剑神 2025-01-02 10:12:16

要回答有关如何提供应用程序范围的事件对象的问题,您可以创建一个名为 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 产品开发的参考架构。

To answer your question as to how to provide an application wide event object, you can create an amd module called globalContext and instantiate it in the main.js.
Thereafter you can attach settings to the globalContext and use the global context to create subcomponents etc.

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

In the global-context.js file we can then perform tasks such as loading child modules

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

This is what we have implemented in BoilerplateJS, a reference architecture for large scale javascript product development.

朦胧时间 2025-01-02 10:12:16

您可以使用初始化模式将任何值注入 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
   };
});

You can use the initialize pattern to inject any value into a requirejs module (aka 'dependency injection').

Do a require call anywhere in your code:

var MyBackboneModule;

MyBackboneModule = someWayToGetAReferenceToIt();

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

With module.js file defined as

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

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

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


   return { 
      initialize: initialize
   };
});
戒ㄋ 2025-01-02 10:12:16

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

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

You can define a single global APP in your entry point AMD module. APP could create and hold a reference to other shared modules:

APP = {
    this.settings : function() {
        if(settingsModule == undefined){
            //require, create and return it
        } else {
            return settingsModule;
        }
    }
}
挽容 2025-01-02 10:12:16

只需对您自己的答案进行评论 - 您不需要在 app_registry 模块中定义函数:

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

应该足够了。

请参阅:文档

不过,请小心这些事情。在某些用例中,共享数据模块是有意义的。但是,如果您最终将其用作伪全局命名空间,那么它并不比仅使用全局变量好多少(并不是说这就是您正在做的事情)。

Just a comment on your own answer - you don't need to define a function in your app_registry module:

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

Should suffice.

See: the docs

Be careful with these things though. There are usecases where shared data modules make sense. But if you end up using it as a pseudo global namespace, it's not much better than just using globals (not saying that's what you're doing though).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文