Come dovrebbe apparire un iniettore di dipendenza in JavaScript?

3

Sto studiando la dipendenza dall'iniezione in JavaScript. Ho imparato cosa devo realizzare, secondo Wikipedia,

The client delegates to external code (the injector) the responsibility of providing its dependencies. The client is not allowed to call the injector code.[2] It is the injecting code that constructs the services and calls the client to inject them. This means the client code does not need to know about the injecting code. The client does not need to know how to construct the services. The client does not need to know which actual services it is using. The client only needs to know about the intrinsic interfaces of the services because these define how the client may use the services.

Ma non sono sicuro di come dovrebbe essere fatto in JavaScript. Probabilmente potrei iniziare a creare ogni sorta di modi per iniettare dipendenze in JavaScript, far corrispondere "servizi" a "clienti" nella struttura del codice e soddisfare tecnicamente i termini di Principio di inversione delle dipendenze . Ma ciò non significa che sarebbe il modo migliore / corretto.

Per esempio, diciamo che ho un wheel (servizio) che ha bisogno di ogni car (client), insieme ai servizi: gasPedal , break , clutch e stick .

  • Che aspetto dovrebbe avere un injector di dipendenza adeguato in JavaScript?
  • Come si fa a iniettare la dipendenza senza chiamare il codice di iniezione dal client?

Nota: nessuna delle risposte finora ha riguardato l'esecuzione di manualmente . So che posso usare le librerie per farlo, quello che sto chiedendo - l'aspetto stimolante degli iniettori - è come crearli da zero, come sarebbe la struttura di uno, non come usare una libreria che li supporti .

Sto cercando di capire quale funzione per un iniettore sarebbe strutturata come per comprendere veramente l'iniezione di dipendenza nel suo nucleo - la funzione che implementa l'iniezione. Non sto chiedendo una funzione completa o un codice funzionante, solo una buona spiegazione o anche un esempio di pseudo-codice eccessivamente semplificato.

    
posta Viziionary 25.09.2015 - 16:48
fonte

2 risposte

4

Come "dovrebbe" essere fatto è un argomento di discussione, ma posso fornirti un esempio che funziona bene da una libreria piuttosto comune - angularjs:

(function() { // wrap in anonymous function to not pollute global scope
    angular
        .module('mymodule') // which module to register this object with
        // register 'someSvc' identifier to inject someSvc object
        // for testing, provide a replacement object
        .service('someSvc', someSvc);

    // the object that will be injected
    function someSvc() {
        var privateVar = '';
        this.publicVar = '';
        this.publicMethod = function() { ... };
    }
})();

Se in seguito utilizzo someSvc in un altro componente (che verrà registrato anche con l'injector delle dipendenze) ...:

(function() { // wrap in anonymous function to not pollute global scope
    angular
        .module('mymodule') // which module to register this object with
        // register someCtrl object with identifier 'someCtrl'
        .controller('someCtrl', someCtrl);

    // tell angular which dependencies this object requires
    // this method of injection survives javascript minification
    someCtrl.$inject = ['someSvc']

    // constructor inject dependencies
    // name someSvc doesn't have to match (since we used $inject above)
    // but kept same for clarity
    function someCtrl(someSvc) {
        this.doSomething = function () {
            someSvc.publicMethod();
        }
    }
    // javascript functions are "hoisted", so it's available even if declared last
})();

Scopes

Esistono diversi metodi di registrazione su angolare che forniscono essenzialmente ambiti diversi come un contenitore DI standard. .service riporta l'oggetto una sola volta (singleton). .factory si aspetta una funzione che restituisce l'oggetto e chiama la funzione una sola volta (singleton). .controller è per ambito di durata dell'oggetto e generalmente utilizzato per i controllori del modello di pagina.

Minimo JS

Devi anche tenere a mente che i nomi delle variabili possono e saranno modificati dal processo di minimizzazione, quindi il tuo metodo di iniezione deve ancora funzionare quando cambiano i nomi delle variabili. In angolare, ciò si ottiene specificando l'identificatore di stringa della dipendenza (tramite $ inject o sintassi dell'array sulla registrazione del modulo).

Iniezione

La sintassi precedente registra le dipendenze con l'iniettore. Le dipendenze vengono iniettate dall'iniettore in questo modo:

// create an injector
var $injector = angular.injector(['ng']);

// use the injector to kick off your application
// use the type inference to auto inject arguments, or use implicit injection
$injector.invoke(function($rootScope, $compile, $document) {
  $compile($document)($rootScope);
  $rootScope.$digest();
});

Esempio estratto da questo link . L'iniettore legge i nomi dei parametri (o la proprietà $ inject) della funzione invocata e tenta di trovare i nomi delle dipendenze corrispondenti nel suo registro. Se non può, allora si blocca. Ovviamente, è responsabilità dell'utente assicurarsi che i moduli appropriati siano registrati prima di chiamare l'iniettore. (Angular chiama automaticamente l'iniettore durante il suo processo di avvio mentre esegue la scansione e trova i componenti registrati specificati nel DOM HTML.)

È possibile trovare ulteriori informazioni sulla DI angolare qui .

    
risposta data 25.09.2015 - 18:13
fonte
1

Ci sono un certo numero di soluzioni esistenti che dovresti esaminare prima di reinventare la ruota. Uno è Definizione di modulo asincrono (AMD) , che è condiviso da alcuni framework e utilizzabile da molti altri. Praticamente tutti i framework di qualsiasi nota hanno risolto questo problema.

La grande differenza con JavaScript rispetto ad altri linguaggi è l'idea che di solito vuoi essere in grado di caricare le dipendenze in modo asincrono sul web su richiesta, e solo quelle di cui hai bisogno, e memorizzarle nella cache per un uso successivo. D'altra parte, si desidera anche la possibilità di compilare tutte le dipendenze in un unico file miniato che è veloce da scaricare per l'uso di produzione, ma avere la versione semanticamente identica alla versione on-demand asincrona utilizzata durante lo sviluppo.

    
risposta data 25.09.2015 - 17:18
fonte