Condividi le risorse tra diversi moduli AMD
-
27-10-2019 - |
Domanda
Attualmente sto sviluppando una nuova applicazione web.
Questa è la prima volta che utilizzo requirejs con i moduli AMD.
Non è così facile abituarsi a quel nuovo paradigma secondo cui non ci sono, a quanto ho capito, variabili nello spazio dei nomi globale.
Nelle precedenti applicazioni web avevo sempre una variabile nello spazio dei nomi globale che potevo utilizzare per condividere diverse risorse tra diversi moduli.
Ora con i moduli AMD requirejs, utilizzo backbone.js e jquery (entrambe le versioni AMD: jquery 1.7.1 e backbone.js 0.5.3-optamd3).
Da qualche parte nella mia applicazione prendo un modulo backbone.js dal server (oggetto utente).Vorrei avere accesso a questo modulo da diversi moduli AMD.Voglio anche avere un oggetto evento a livello di applicazione.
Potresti dirmi:qual è il modo giusto in requirejs AMD di condividere le risorse tra diversi moduli?
Soluzione
Ho trovato una soluzione da solo.
Grazie, IntoTheVoid, per la tua risposta, ma speravo in una soluzione simile ad AMD.Ciò significa, non ancora una volta, "inquinare" lo spazio dei nomi globale.
C'erano 2 chiavi per la mia soluzione:
"https://github.com/addyosmani/backbone-aura" da Addy Osmani e "https://github.com/amdjs/amdjs-api/wiki/AMD" la specifica API AMD (Asynchronous Module Definition).
Le specifiche dicono:"Se la factory è una funzione, dovrebbe essere eseguita solo una volta."
Pertanto, se un modulo amd viene specificato più volte come dipendenza in un'applicazione web, la dipendenza non è solo NON CARICATO PIÙ VOLTE, è altresì NON ESEGUITO PIÙ VOLTE, e questa è la novità per me.Viene eseguito una sola volta e viene mantenuto il valore restituito dalla funzione factory.Ogni dipendenza con lo stesso percorso ha lo stesso oggetto.E questo cambia tutto.
Quindi, definisci semplicemente il seguente modulo amd:
define([], function() {
var app_registry = {};
app_registry.global_event_obj = _.extend({}, Backbone.Events);
app_registry.models = {};
return app_registry;
});
Ora, in quei moduli in cui desideri condividere le risorse, dichiari questo modulo app_registry come dipendenza e scrivi in uno:
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;
}
...
e nell'altro:
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. ...
}
...
Altri suggerimenti
Per rispondere alla tua domanda su come fornire un oggetto evento a largo applicazione, è possibile creare un modulo AMD chiamato GlobalContext e istanziarlo in Main.js.
Successivamente è possibile allegare le impostazioni a GlobalContext e utilizzare il contesto globale per creare sottocomponenti ecc.
//main.js file
require([ "./global-context" ], function( GlobalContext) {
new GlobalContext();
});
Nel file globale-conftext.js possiamo quindi eseguire attività come il caricamento di moduli figlio
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);
};
Questo è ciò che abbiamo implementato BoilerPlatejs, un'architettura di riferimento per lo sviluppo del prodotto JavaScript su larga scala.
È possibile utilizzare il pattern Initialize per iniettare qualsiasi valore in un modulo requisito (aka "Iniezione di dipendenza").
Fai una chiamata a richiedere ovunque nel tuo codice:
var MyBackboneModule;
MyBackboneModule = someWayToGetAReferenceToIt();
require("module", function(Module) {
Module.initialize(MyBackboneModule);
});
Con il file module.js definito come
define([], function(){
var BackboneModuleDoingThisAndThat;
function initialize(pBackboneModule) {
BackboneModuleDoingThisAndThat = pBackboneModule ;
};
function doSomething() {
var x = BackboneModuleDoingThisAndThat.computeThis(42);
};
return {
initialize: initialize
};
});
Puoi definire un singolo globale APP
Nel tuo punto di ingresso modulo AMD. APP
potrebbe creare e tenere un riferimento ad altri moduli condivisi:
APP = {
this.settings : function() {
if(settingsModule == undefined){
//require, create and return it
} else {
return settingsModule;
}
}
}
Solo un commento sulla tua risposta: non è necessario definire una funzione nel modulo App_registry:
define({
global_event_obj: _.extend({}, Backbone.Events);
models: {}
});
Dovrebbe essere sufficiente.
Vedere: i documenti
Fai attenzione a queste cose però. Ci sono usecasi in cui i moduli di dati condivisi hanno senso. Ma se finisci per usarlo come uno spazio dei nomi globale pseudo, non è molto meglio che usare i globali (non dire che è quello che stai facendo però).