@ teqfw / di

Certains adorent faire du vĂ©lo et d'autres adorent les rĂ©inventer. Je fais partie de ceux qui rĂ©inventent les vĂ©los pour les rouler. Il y a quelques annĂ©es, j'ai dĂ©jĂ  Ă©crit sur Habr Ă  propos de mon " vĂ©lo " - un conteneur DI pour JavaScript. La discussion qui a suivi sur les principes de fonctionnement des conteneurs DI et leur diffĂ©rence par rapport au " Service Locator " m'a beaucoup avancĂ© dans la comprĂ©hension du travail de mon propre " vĂ©lo " et a abouti non seulement Ă  un certain nombre d' articles sur HabrĂ© ( un , deux , trois , quatre ), mais aussi dans une large mesure l'achĂšvement du " vĂ©lo " lui-mĂȘme.





Sous la coupe - une description du travail du conteneur DI ( @ teqfw / di ) à partir du moment actuel. Limitations : le conteneur est écrit en pur JavaScript (ES2015 +), ne fonctionne qu'avec du code ES2015 +, décoré en modules ES avec l'extension *.mjs



. Avantages : permet de charger et d'utiliser les mĂȘmes modules Ă  la fois dans le navigateur et dans les applications nodejs sans transpilation supplĂ©mentaire.





Principes de base des conteneurs DI

Un appel typique Ă  un conteneur abstrait d'objets ressemble Ă  ceci :





const obj = container.get(id);
      
      



La séquence d'actions du conteneur :





  1. Déterminez par id quel type d'objet l'appelant veut obtenir.





  2. Vérifiez la présence de l'objet demandé dans le conteneur, si l'objet est dans le conteneur, renvoyez-le.





  3. Si l'objet doit ĂȘtre créé, utilisez l'ID pour dĂ©terminer oĂč se trouve le fichier contenant le code source de l'objet et tĂ©lĂ©chargez les sources.





  4. ( ).





  5. .





  6. .





  7. ( ).





  8. .





— 5 , , .





ES-

, ES- — .., DI- ES-.





const obj = {name: 'Simple Object'};
class Clazz {
    constructor(spec) {
        this.name = 'instance from class constructor';
    }
}
function Factory(spec) {
    return {name: 'instance from factory'};
}
export {
    obj as ObjTmpl,
    Clazz as default,
    Factory,
}
      
      



, ES- (, ):





import Def from './es6.mjs';
import {Factory} from './es6.mjs';
import {ObjTmpl} from './es6.mjs';

const spec = {}; // empty specification
const instClass = new Def(spec);
const instFact = Factory(spec);
const instTmpl = Object.assign(ObjTmpl, {});
      
      



, DI-, ES-, :





  • ;





  • ;





— , , ( ) , DI- :





constructor(spec) {
    const dep = spec['depId'];
}
...
await container.get('dep1');
      
      



:





import Container from '@teqfw/di';

const container = new Container();
container.set('dep1', {name: 'first'});
container.set('dep2', {name: 'second'});

const obj = await container.get('dep1');
      
      



ES-, (, -).





@teqfw/di



:





  • : (connection



    , conf



    , i18n



    , 
);





  • : (EsModuleId



    );





container.set(id, obj)



, ( ).





@teqfw/di



ES- , Module



(. “” “Javascript: ”).





, - . @teqfw/di



#



:





  • EsModuleId



    : ;





  • EsModuleId#ExportName



    : ExportName



    EsModuleId



    ;





  • EsModuleId#default



    EsModuleId#



    : default



    EsModuleId



    ;





@teqfw/di



:





class Clazz {
    constructor(spec) {}
}

function Factory(spec) {}
      
      



, (), — ( )? @teqfw/di



$



:





  • EsModuleId#ExportName



    : (, ) ExportName



    EsModuleId



    .





  • EsModuleId#ExportName$



    : , ( ), ExportName



    EsModuleId



    .





default



- ES- :





  • EsModuleId#default$







  • EsModuleId#$







  • EsModuleId$







Singleton

( ), . "" -$$



:





  • EsModuleId$



    EsModuleId#ExportName$



    : ( ) , .





  • EsModuleId$$



    EsModuleId#ExportName$$



    : .





, singleton’ — . DI- global-. - , , DI — .





@teqfw/di



:





let id1 = 'named'; // named singleton been added manually
let id2 = 'EsModId'; // ES module
let id3 = 'EsModId#'; // default export of ES module
let id4 = 'EsModId#name'; // named export of ES module
let id5 = 'EsModId$'; // singleton from default export
let id6 = 'EsModId$$'; // new instance from default export
let id7 = 'EsModId#name$'; // singleton from named export
let id8 = 'EsModId#name$$'; // new instance from named export
      
      



, , , ( ). @teqfw/di



:





constructor(spec) {
    const named = spec['namedSingleton'];
    const inst = spec['EsModId#name$$'];
    const single = spec['EsModId$'];
}
      
      



@teqfw/di



, , , , . , , .





ES-, . @teqfw/di



:





container.addSourceMapping('EsModId', './relative/path');
container.addSourceMapping('EsModId', '/absolute/path', true);
      
      



( ) , , — nodejs-. , .





, , , namespace’, _



:





EsModId_PathTo_Mod => /absolute/path/PathTo/Mod.mjs
      
      



Le conteneur @ teqfw / di DI vous permet d'utiliser les deux modules ES eux-mĂȘmes comme dĂ©pendances, ainsi que des Ă©lĂ©ments individuels de l'exportation de modules ES, ainsi que de crĂ©er de nouvelles instances d'objets ou d'utiliser un seul objet pour l'ensemble de l'application. De plus, le mĂȘme code peut ĂȘtre utilisĂ© Ă  la fois dans les navigateurs et dans les applications nodejs.





Code type pour un module ES utilisé dans @teqfw/di



:





export default class Mod {
    constructor(spec) {
        const Clazz = spec['Lib_Dep#'];
        const single = spec['Lib_Dep$'];
        const inst = spec['Lib_Dep$$'];
        // ...
    }
}
      
      



L'habituel import



peut Ă©galement ĂȘtre utilisĂ© dans le code, mais dans ce cas, le code perd la possibilitĂ© d'ĂȘtre utilisĂ© simultanĂ©ment dans les navigateurs et dans les applications nodejs, car le format d'import du navigateur n'est pas compatible avec le format nodejs.








All Articles