Maison  >  Article  >  interface Web  >  Modèles de conception d'architecture d'application JavaScript à grande échelle (avancé)

Modèles de conception d'architecture d'application JavaScript à grande échelle (avancé)

亚连
亚连original
2018-05-21 09:23:512604parcourir

Ce qui suit est un modèle de conception d'architecture d'application JavaScript à grande échelle que j'ai compilé pour vous. Les étudiants intéressés peuvent y jeter un œil.

Voici les principaux chapitres de cet article :

1. Qu'est-ce qu'un « grand programme JavaScript » ?

2. Considérez l'architecture actuelle du programme

3. Pensez à long terme

4. Réfléchissez

5. 5.1 Modèle de conception

5.1.1 Théorie du module

5.1.1.1 Présentation

5.1.1.2 Mode module

5.1.1.3 Valeur faciale de l'objet

5.1.1.4 Module CommonJS

5.1.2 Mode façade

5.1.3 Mode médiateur

5.2 Appliquer à votre architecture

5.2 .1 Façade - abstraction du noyau

5.2.2 Médiateur - noyau du programme

5.2.3 Travailler en étroite collaboration

6. Extension de la publication/abonnement à Sub : inscription automatique Événements

7. Questions et réponses

8. Remerciements

Qu'est-ce qu'un « grand programme JavaScript » ?

Avant de commencer, définissons ce qu'est un grand site JavaScript. De nombreux experts expérimentés en développement JS ont également été mis au défi. Certaines personnes disent que plus de 100 000 lignes de code JavaScript sont également considérées comme volumineuses. disons que la taille du code JavaScript doit dépasser 1 Mo. En fait, aucune des deux n'est correcte, car elle ne peut pas être mesurée par la quantité de code installé. De nombreux codes JS triviaux peuvent facilement dépasser 100 000 lignes.

Ma définition de « grand » est la suivante, même si elle n'est peut-être pas correcte, elle devrait être relativement proche :

Je pense personnellement que les grands programmes JavaScript devraient être très importants et intégré dans Il s'agit d'un programme qui utilise les efforts de nombreux développeurs exceptionnels pour traiter des données lourdes et les afficher dans le navigateur.

En examinant l'architecture actuelle du programme

Je ne peux pas souligner l'importance de cette question, de nombreux développeurs expérimentés disent souvent : "Les idées et les modèles de conception existants ont très bien fonctionné sur mon dernier projet de taille moyenne, donc cela ne devrait poser aucun problème de l'utiliser à nouveau dans un programme légèrement plus grand, n'est-ce pas ? "C'est vrai pour certains programmes, mais n'oubliez pas, car c'est un gros programme, et il devrait généralement y en avoir. être de grandes préoccupations qui doivent être décomposées et auxquelles il faut prêter attention. J'expliquerai brièvement qu'il faut du temps pour revoir l'architecture du programme qui fonctionne depuis longtemps. Dans la plupart des cas, l'architecture actuelle du programme JavaScript devrait ressembler à ce qui suit (notez qu'il s'agit d'une architecture JS, pas de l'ASP.NET MVC que nous appelons souvent) :

widgets personnalisés

modèles
vues
contrôleurs
modèles
bibliothèques/kits d'outils
un noyau d'application.

Vous pouvez également encapsuler le programme dans plusieurs modules séparément, ou utiliser d'autres modèles de conception, ce qui est bien, mais si ces structures représentent complètement votre architecture, il peut y avoir des problèmes potentiels. Jetons un coup d'œil à quelques points importants :

1 Combien d'éléments de votre architecture peuvent être retirés immédiatement ?

Existe-t-il des modules distincts qui ne dépendent pas d'un autre code ? Est-il autonome ? Si je vais dans la base de code que vous utilisez et sélectionne au hasard un code de module, puis que je le mets sur une nouvelle page, sera-t-il disponible immédiatement ? Vous direz peut-être que le principe est suffisant, je vous suggère d'y réfléchir longuement. Si votre entreprise a déjà développé de nombreux programmes importants, un jour, quelqu'un dira que le module de chat de ce projet est bon et supprimons-le. mettez-le dans un autre projet Allez, pouvez-vous simplement le prendre et l'utiliser sans modifier le code ?

2. Combien de modules du système doivent dépendre d'autres modules ?

Les différents modules du système sont-ils étroitement couplés ? Avant d'aborder cette question, permettez-moi d'abord d'expliquer que cela ne signifie pas que tous les modules ne doivent avoir aucune dépendance. Par exemple, une fonction à granularité fine peut être étendue à partir de la fonction de base. Mon problème est différent de cette situation. , je parle des dépendances entre les différents modules fonctionnels. En théorie, tous les différents modules fonctionnels ne devraient pas avoir trop de dépendances.

3. Si une certaine partie de votre programme échoue, d'autres parties peuvent-elles encore fonctionner ?

Si vous créez un programme similaire à Gmail, vous pouvez constater que de nombreux modules dans Gmail sont chargés dynamiquement. Par exemple, le module de discussion n'est pas chargé lorsque la page est initialisée, et même si une erreur se produit après le chargement, la page. D'autres pièces peuvent également être utilisées normalement.

4. Chacun de vos modules peut-il être facilement testé ? Chacun de vos modules peut être utilisé sur un grand site avec des millions d'utilisateurs, ou même utilisé par plusieurs sites, votre module doit donc être capable de résister aux tests, c'est-à-dire s'il est dans l'architecture. Cela devrait être facile pour tester s'il est externe à l'architecture, notamment que la plupart des assertions peuvent être transmises dans différents environnements.

Pensez au long terme

Lors de la construction d'un grand programme, le plus important est d'être tourné vers l'avenir. On ne peut pas se contenter de considérer la situation sur un mois. ou dans un an, mais pensez également à l’avenir. Quelles sont les possibilités de changement à long terme ? Les développeurs lient souvent trop étroitement le code de manipulation du DOM au programme, même s'ils ont parfois encapsulé une logique distincte dans différents modules. Pensez-y, pourquoi n'est-ce pas bon à long terme ?

Un de mes collègues a dit un jour qu'une architecture précise peut ne pas être adaptée aux scénarios futurs. C'est parfois vrai, mais lorsque vous devez le faire, l'argent que vous devez payer est assez élevé. Par exemple, vous devrez peut-être choisir et remplacer entre Dojo, jQuery, Zepto et YUI pour certaines raisons de performances, de sécurité et de conception. À ce stade, il y aura un problème avec des dépendances, ce qui nécessite de l'argent et du temps. . , nous avons besoin de monde, non ?

C'est bien pour certains petits sites, mais les grands sites doivent vraiment fournir un mécanisme plus flexible sans se soucier de divers problèmes entre les différents modules. Cela permet non seulement d'économiser de l'argent, mais aussi du temps.

Pour résumer, êtes-vous sûr maintenant de pouvoir remplacer certaines bibliothèques de classes sans réécrire tout le programme ? Sinon, je suppose que ce dont nous allons parler ci-dessous vous conviendra mieux.

De nombreux développeurs JavaScript expérimentés ont donné quelques notes clés :

Justin Meyer, auteur de JavaScriptMVC a déclaré :

Construire de grands programmes est le plus grand. Le secret est ne jamais construire de grands programmes, mais diviser le programme en petits modules afin que chaque petit module puisse être testé, dimensionné, puis intégré au programme.

Nicholas Zakas, auteur de Sites Web JavaScript haute performance :
"La clé est de reconnaître dès le début que vous n'avez aucune idée de la façon dont cela va se développer. Lorsque vous acceptez que vous ne savez pas tout, vous commencez à concevoir le système de manière défensive. Vous identifiez les domaines clés qui peuvent changer, ce qui est souvent très facile lorsque vous y consacrez un peu de temps. Par exemple, vous devez vous attendre à ce que toute partie de l'application communique avec un autre système. va probablement changer, vous devez donc faire abstraction de cela. " -

Beaucoup de problèmes de texte sont trop gênants. Pour résumer, tout est modifiable, donc cela doit être abstrait.

Rebecca Murphey, auteur de JQuery Fundamentals :
Plus la connexion entre chaque module est étroite, moins elle est réutilisable et plus il est difficile de la modifier.

Ces points importants ci-dessus sont les éléments essentiels de la construction d’une architecture, et nous devons les garder à l’esprit à tout moment.

Brainstorming

Réfléchissons. Nous avons besoin d'une architecture faiblement couplée. Il n'y a pas de dépendances entre les modules. Chaque module communique avec le programme, puis au milieu La couche. prend le relais et traite les retours des messages correspondants.

Par exemple, si nous disposons d'un code JavaScript pour créer un programme de boulangerie en ligne, un module envoie un message qui peut être "42 petits pains doivent être livrés". Nous utilisons différentes couches pour traiter les messages envoyés par le module, comme suit :

Le module n'accède pas directement au noyau du programme
Le module n'appelle ni n'affecte directement les autres modules

Cela nous évitera de provoquer des erreurs dans tous les modules en raison d'une erreur dans un module.

Un autre problème est la sécurité. La situation réelle est que la plupart des gens ne pensent pas que la sécurité intérieure est un problème. Nous disons dans nos cœurs, j'ai construit le programme moi-même, et je sais lesquels sont publics et lesquels. sont privés. La sécurité ne pose pas de problème, mais existe-t-il un moyen de définir quel module est autorisé à accéder au cœur du programme ? Par exemple, s'il y a un module de discussion, je ne veux pas qu'il appelle le module d'administration, ou je ne veux pas qu'il appelle un module avec des autorisations d'écriture dans la base de données, car la relation entre eux est très fragile et peut facilement conduire aux attaques XSS. Chaque module ne devrait pas être capable de tout faire, mais c'est le problème du code JavaScript dans la plupart des architectures actuelles. Fournissez une couche intermédiaire pour contrôler quel module peut accéder à la partie autorisée. En d'autres termes, le module ne peut faire que la partie la plus autorisée.

Architecture proposée

L'objet de notre article est ici cette fois, notre architecture proposée utilise des modèles de conception que nous connaissons tous : module, façade et médiateur.

Différent du modèle traditionnel, afin de découpler chaque module, nous laissons le module publier uniquement certains événements. Le mode médiateur peut se charger de souscrire les messages de ces modules, puis de contrôler la réponse de la notification. , mode façade Les utilisateurs limitent les autorisations de chaque module.

Voici les parties auxquelles nous devons prêter attention :
1 Modèle de conception
1.1 Théorie du module
1.1.1 Présentation
1.1.2 Mode module
1.1.3 Objet depuis valeur nominale
                                                                                                                                                                    Modèle de façade Médiateur - Noyau du programme
2.3 Intégration étroite Comment ça marche


Théorie des modules

Tout le monde a peut-être utilisé du code modulaire pour une plus grande ou dans une moindre mesure. Un module fait partie d'une architecture de programme complète et robuste. Chaque module est créé à des fins distinctes. Revenons à Gmail, prenons un exemple. Le module de discussion ressemble à une partie distincte. sous-modules. Par exemple, le module émoticône à l'intérieur est en fait une partie distincte. Le sous-module est également utilisé dans la fenêtre d'envoi d'e-mails.

L'autre est que les modules peuvent être chargés, supprimés et remplacés dynamiquement.

En JavaScript, nous avons plusieurs façons d'implémenter des modules. Les plus connues sont le mode module et les littéraux objet. Si vous les connaissez déjà, veuillez ignorer cette section et passer directement à la partie CommonJS.

Modèle de module

Le modèle de module est un modèle de conception populaire. Il peut encapsuler des variables privées, des méthodes et des états via des accolades en enveloppant ces contenus, généralement des objets globaux. n'est pas accessible directement. Dans ce modèle de conception, une seule API est renvoyée et tous les autres contenus sont encapsulés comme privés.

De plus, ce mode est similaire à l'expression de fonction auto-exécutable. La seule différence est que le module renvoie un objet, tandis que l'expression de fonction auto-exécutable renvoie une fonction.

Comme nous le savons tous, JavaScript n'a pas de modificateurs d'accès comme les autres langages. Il ne peut pas déclarer de modificateurs privés et publics pour chaque champ ou méthode. Alors, comment implémenter ce modèle ? Il s'agit de renvoyer un objet contenant des méthodes publiques. Ces méthodes ont la capacité d'appeler des objets internes.

Regardez le code suivant. Ce code est un code auto-exécutable. La déclaration inclut un objet global basketModule. Le tableau panier est privé, donc l'ensemble de votre programme ne peut pas accéder à ce tableau privé en même temps. nous avons renvoyé un objet qui contient trois méthodes (telles que addItem, getItemCount, getTotal). Ces trois méthodes peuvent accéder au tableau du panier privé.

En même temps, notez que l'objet que nous retournons est directement affecté à basketModule, nous pouvons donc l'utiliser comme suit :

C'est dans diverses bibliothèques de classes populaires (comme Dojo, Comment le faire dans jQuery) ?
var basketModule = (function() {
var basket = []; //private
return { //exposed to public
  addItem: function(values) {
    basket.push(values);
  },
  getItemCount: function() {
    return basket.length;
  },
  getTotal: function(){
    var q = this.getItemCount(),p=0;
    while(q--){
    p+= basket[q].price;
    }
    return p;
  }
 }
}());

//basketModule is an object with properties which can also be methods
basketModule.addItem({item:'bread',price:0.5});
basketModule.addItem({item:'butter',price:0.3});
 
console.log(basketModule.getItemCount());
console.log(basketModule.getTotal());
 
//however, the following will not work:
console.log(basketModule.basket);// (undefined as not inside the returned object)
console.log(basket); //(only exists within the scope of the closure)
Dojo

Dojo essaie d'utiliser dojo.declare pour fournir une déclaration de style classe Nous pouvons l'utiliser pour implémenter le modèle Module, par exemple si vous souhaitez déclarer l'objet panier sous l'espace de noms du magasin, vous pouvez faire ceci : Utilisez-le en conjonction avec dojo.provide, qui est très puissant.

//traditional way
var store = window.store || {};
store.basket = store.basket || {};
 
//using dojo.setObject
dojo.setObject("store.basket.object", (function() {
  var basket = [];
  function privateMethod() {
    console.log(basket);
  }
  return {
    publicMethod: function(){
      privateMethod();
    }
   };
}()));
YUI

Le code suivant est l'implémentation originale de YUI :

jQuery

YAHOO.store.basket = function () {

 //"private" variables:
 var myPrivateVar = "I can be accessed only within YAHOO.store.basket .";

 //"private" method:
 var myPrivateMethod = function () {
 YAHOO.log("I can be accessed only from within YAHOO.store.basket");
 }

 return {
 myPublicProperty: "I'm a public property.",
 myPublicMethod: function () {
  YAHOO.log("I'm a public method.");

  //Within basket, I can access "private" vars and methods:
  YAHOO.log(myPrivateVar);
  YAHOO.log(myPrivateMethod());

  //The native scope of myPublicMethod is store so we can
  //access public members using "this":
  YAHOO.log(this.myPublicProperty);
 }
 };

} ();

Il existe de nombreuses implémentations du modèle Module dans jQuery. Regardons un autre exemple. Une fonction de bibliothèque déclare une nouvelle bibliothèque, puis lors de la création de la bibliothèque, dans le document. La méthode init est automatiquement exécutée en mode prêt.

Valeur faciale de l'objet

function library(module) {
  $(function() {
    if (module.init) {
      module.init();
    }
  });
  return module;
}
 
var myLibrary = library(function() {
  return {
    init: function() {
      /*implementation*/
      }
  };
}());

La valeur faciale de l'objet est déclarée à l'aide d'accolades, et il n'est pas nécessaire d'utiliser le new mot-clé lors de son utilisation, si vous ne vous souciez pas beaucoup du caractère public/privé des champs d'attribut dans un module, vous pouvez utiliser cette méthode, mais veuillez noter que cette méthode est différente de JSON. Visage de l'objet : var item={name : "tom", value:123} JSON : var item={"name":"tom", "value":123}.

CommonJS

var myModule = {
 myProperty: 'someValue',
 //object literals can contain properties and methods.
 //here, another object is defined for configuration
 //purposes:
 myConfig: {
 useCaching: true,
 language: 'en'
 },
 //a very basic method
 myMethod: function () {
 console.log('I can haz functionality?');
 },
 //output a value based on current configuration
 myMethod2: function () {
 console.log('Caching is:' + (this.myConfig.useCaching) ? 'enabled' : 'disabled');
 },
 //override the current configuration
 myMethod3: function (newConfig) {
 if (typeof newConfig == 'object') {
  this.myConfig = newConfig;
  console.log(this.myConfig.language);
 }
 }
};

 
myModule.myMethod(); //I can haz functionality
myModule.myMethod2(); //outputs enabled
myModule.myMethod3({ language: 'fr', useCaching: false }); //fr

Je ne dirai pas grand-chose sur l'introduction de CommonJS ici. Il a été présenté dans de nombreux articles précédents. Nous allons le présenter ici. Ce que je veux mentionner, c'est qu'il y a deux paramètres importants dans le standard CommonJS, exports et require Exports représentent les modules à charger, et require représente que ces modules chargés doivent dépendre d'autres modules et également. besoin d'être chargé. Il existe de nombreuses implémentations de chargement de modules standard CommonJS. Celle que je préfère est RequireJS. Peut-il très bien charger les modules et les modules dépendants associés ? Voici un exemple simple, comme la nécessité de convertir des images. en code ASCII, nous chargeons d'abord le module encodeur, puis obtenons sa méthode encodeToASCII Théoriquement, le code devrait être le suivant :

.
var encodeToASCII = require("encoder").encodeToASCII;
exports.encodeSomeSource = function(){
  //其它操作以后,然后调用encodeToASCII
}

但是上述代码并没用工作,因为encodeToASCII函数并没用附加到window对象上,所以不能使用,改进以后的代码需要这样才行:

define(function(require, exports, module) {
  var encodeToASCII = require("encoder").encodeToASCII;
    exports.encodeSomeSource = function(){
    //process then call encodeToASCII
  }
});

CommonJS 潜力很大,但是由于大叔不太熟,所以就不过多地介绍了。

Facade模式

Facade模式在本文架构里占有重要角色,关于这个模式很多JavaScript类库或者框架里都有体现,其中最大的作用,就是包括High level的API,以此来隐藏具体的实现,这就是说,我们只暴露接口,内部的实现我们可以自己做主,也意味着内部实现的代码可以很容易的修改和更新,比如今天你是用jQuery来实现的,明天又想换YUI了,这就非常方便了。

下面这个例子了,可以看到我们提供了很多私有的方法,然后通过暴露一个简单的 API来让外界执行调用内部的方法:

var module = (function () {
 var _private = {
 i: 5,
 get: function () {
  console.log('current value:' + this.i);
 },
 set: function (val) {
  this.i = val;
 },
 run: function () {
  console.log('running');
 },
 jump: function () {
  console.log('jumping');
 }
 };
 return {
 facade: function (args) {
  _private.set(args.val);
  _private.get();
  if (args.run) {
  _private.run();
  }
 }
 }
} ());

module.facade({run:true, val:10});
//outputs current value: 10, running

Facade和下面我们所说的mediator的区别是,facade只提供现有存在的功能,而mediator可以增加新功能。

 Mediator模式

讲modiator之前,我们先来举个例子,机场飞行控制系统,也就是传说中的塔台,具有绝对的权利,他可以控制任何一架飞机的起飞和降落时间以及地方,而飞机和飞机之前不允许通信,也就是说塔台是机场的核心,mediator就相当于这个塔台。

mediator就是用在程序里有多个模块,而你又不想让各个模块有依赖的话,那通过mediator模式可以达到集中控制的目的。实际场景中也是,mediator封装了很多不想干的模块,让他们通过mediator联系在一起,同时也松耦合他们,使得他们之间必须通过mediator才能通信。

那mediator模式的优点是什么?那就是解耦,如果你之前对观察者模式比较了解的话,那理解下面的mediator图就相对简单多了,下图是一个high level的mediator模式图:

Modèles de conception darchitecture dapplication JavaScript à grande échelle (avancé)

想想一下,各模块是发布者,mediator既是发布者又是订阅者。

    Module 1向Mediator广播一个实际,说需要做某事
    Mediator捕获消息以后,立即启动处理该消息需要使用的Module 2,Module 2处理结束以后返回信息给Mediator
    与此同时,Mediator也启动了Module 3,当接受Module 2 返回消息的时候自动记录日志到Module 3里

可以看到,各模块之间并没有通信,另外Mediator也可以实现监控各模块状态的功能,例如如果Module 3出错了,Mediator可以暂时只想其它模块,然后重启Module 3,然后继续执行。

回顾一下,可以看到,Mediator的优点是:松耦合的模块由同一的Mediator来控制,模块只需要广播和监听事件就可以了,而模块之间不需要直接联系,另外,一次信息的处理可以使用多个模块,也方便我们以后统一的添加新的模块到现有的控制逻辑里。

确定是:由于所有的模块直接都不能直接通信,所有相对来说,性能方面可能会有少许下降,但是我认为这是值得的。

我们根据上面的讲解来一个简单的Demo:

var mediator = (function(){
 var subscribe = function(channel, fn){
 if (!mediator.channels[channel]) mediator.channels[channel] = [];
 mediator.channels[channel].push({ context: this, callback: fn });
 return this;
 },
 
 publish = function(channel){
 if (!mediator.channels[channel]) return false;
 var args = Array.prototype.slice.call(arguments, 1);
 for (var i = 0, l = mediator.channels[channel].length; i < l; i++) {
  var subscription = mediator.channels[channel][i];
  subscription.callback.apply(subscription.context, args);
 }
 return this;
 };
 
 return {
 channels: {},
 publish: publish,
 subscribe: subscribe,
 installTo: function(obj){
  obj.subscribe = subscribe;
  obj.publish = publish;
 }
 };
 
}());

然后有2个模块分别调用:

//Pub/sub on a centralized mediator
 
mediator.name = "tim";
mediator.subscribe(&#39;nameChange&#39;, function(arg){
 console.log(this.name);
 this.name = arg;
 console.log(this.name);
});
 
mediator.publish(&#39;nameChange&#39;, &#39;david&#39;); //tim, david
 
 
//Pub/sub via third party mediator
 
var obj = { name: &#39;sam&#39; };
mediator.installTo(obj);
obj.subscribe(&#39;nameChange&#39;, function(arg){
 console.log(this.name);
 this.name = arg;
 console.log(this.name);
});
 
obj.publish(&#39;nameChange&#39;, &#39;john&#39;); //sam, john

应用Facade: 应用程序核心的抽象

一个facade是作为应用程序核心的一个抽象来工作的,在mediator和模块之间负责通信,各个模块只能通过这个facade来和程序核心进行通信。作为抽象的职责是确保任何时候都能为这些模块提供一个始终如一的接口(consistent interface),和sendbox controller的角色比较类似。所有的模块组件通过它和mediator通信,所以facade需要是可靠的,可信赖的,同时作为为模块提供接口的功能,facade还需要扮演另外一个角色,那就是安全控制,也就是决定程序的哪个部分可以被一个模块访问,模块组件只能调用他们自己的方法,并且不能访问任何未授权的内容。例如,一个模块可能广播dataValidationCompletedWriteToDB,这里的安全检查需要确保该模块拥有数据库的写权限。

总之,mediator只有在facade授权检测以后才能进行信息处理。

应用Mediator:应用程序的核心

Le médiateur constitue le rôle principal de l'application. Parlons brièvement de ses responsabilités. La tâche principale consiste à gérer le cycle de vie du module. Lorsque ce noyau capture des informations entrantes, il doit déterminer comment le programme doit les gérer, c'est-à-dire décider quel ou quels modules démarrer ou arrêter. Lorsqu'un module démarre, il doit pouvoir s'exécuter automatiquement, sans que le cœur de l'application décide s'il doit être exécuté (par exemple, s'il peut être exécuté lorsque le DOM est prêt), le module lui-même doit donc prendre une décision.

Vous vous posez peut-être encore des questions, c'est-à-dire dans quelles circonstances un module va-t-il s'arrêter. Lorsque le programme détecte qu'un module est en panne ou qu'une erreur s'est produite, le programme doit prendre une décision pour empêcher la méthode du module de continuer à être exécutée afin que le composant puisse être redémarré. L'objectif principal est d'améliorer l'utilisateur. expérience.

De plus, le noyau devrait être capable d'ajouter ou de supprimer dynamiquement des modules sans affecter les autres fonctions. Un exemple courant est qu'un module n'est pas disponible au début du chargement de la page, mais après l'opération de l'utilisateur, le module doit être chargé et exécuté dynamiquement, tout comme la fonction de chat dans Gmail, il devrait l'être. très bien. Comprenez-le.

La gestion des erreurs d'exception est également gérée par le cœur de l'application. De plus, lorsque chaque module diffuse des informations, il diffuse également les erreurs éventuelles au cœur, afin que le cœur du programme puisse arrêter/redémarrer ces modules en fonction de la situation. . Il s'agit également d'une partie importante de l'architecture faiblement couplée. Nous n'avons pas besoin de modifier manuellement les modules. Nous pouvons le faire en utilisant la publication/abonnement via le médiateur.

Assemblez-le

Chaque module contient diverses fonctions dans le programme Lorsqu'ils ont des informations à traiter, ils publient des informations pour informer le programme (c'est leurs principales responsabilités). , comme mentionné dans la section QA ci-dessous, les modules peuvent s'appuyer sur certaines méthodes de fonctionnement des outils DOM, mais ils ne doivent pas dépendre d'autres modules du système. Un module ne doit pas se concentrer sur le contenu suivant :

1. Lequel. objet Ou le module s'abonne aux informations publiées par ce module
2. Ces objets sont-ils des objets côté client ou des objets côté serveur
3. Combien d'objets se sont abonnés à vos informations

Modèles de conception darchitecture dapplication JavaScript à grande échelle (avancé)

Facade fait abstraction du cœur de l'application et évite la communication directe entre les modules. Elle s'abonne aux informations de chaque module et est également responsable de la détection des autorisations pour garantir que chaque module dispose de sa propre autorisation distincte.

Modèles de conception darchitecture dapplication JavaScript à grande échelle (avancé)

Mediator (noyau de l'application) utilise le mode médiateur pour jouer le rôle de gestionnaire de publication/abonnement. Il est responsable de la gestion des modules et du démarrage/arrêt de l'exécution du module. charger et redémarrer dynamiquement le module avec des erreurs.

Modèles de conception darchitecture dapplication JavaScript à grande échelle (avancé)

Le résultat de cette architecture est le suivant : il n'y a pas de dépendances entre les modules. En raison des applications faiblement couplées, elles peuvent être facilement testées et entretenues, et chaque module peut l'être facilement. peut être réutilisé dans d’autres projets et peut être ajouté et supprimé dynamiquement sans affecter le programme.

Extension de publication/abonnement : inscription automatique aux événements

Concernant les événements d'inscription automatique, certaines conventions de dénomination doivent être respectées, par exemple si un module lorsqu'un événement nommé messageUpdate est publié, tous les modules avec la méthode messageUpdate seront automatiquement exécutés. Il y a des avantages et des inconvénients. Pour la méthode d'implémentation spécifique, vous pouvez lire mon autre article : Magic Upgraded Version of jQuery Custom Binding.

QA
1. Est-il possible de ne pas utiliser le mode façade ou bac à sable similaire ?

Bien que les grandes lignes de l'architecture proposent que la façade puisse implémenter la fonction de contrôle d'autorisation, en fait, il est tout à fait possible pour le médiateur de le faire. Ce que l'architecture légère doit faire est en fait presque la même chose. c'est-à-dire un découplage pour garantir que chaque module est directement Il n'y a aucun problème de communication avec le cœur de l'application.

2. Vous avez amélioré le fait que le module ne peut pas avoir de dépendances directement. Cela signifie-t-il qu'il ne peut pas s'appuyer sur des bibliothèques tierces (telles que jQuery).

Il s'agit en fait d'un problème à deux faces. Comme nous l'avons mentionné ci-dessus, un module peut avoir des sous-modules, ou des modules de base, tels que des classes d'outils de manipulation DOM de base. À ce niveau, nous pouvons utiliser des modules tiers. bibliothèques du parti, mais assurez-vous que nous pouvons facilement les remplacer.

3. J'aime cette architecture et je souhaite commencer à l'utiliser. Existe-t-il des exemples de code auxquels je peux me référer ?

Je vais créer un exemple de code pour la référence de chacun, mais avant cela, vous pouvez vous référer à l'article d'Andrew Burgees Writing Modular JavaScript.

4. Si le module doit communiquer directement avec le cœur de l'application, est-ce faisable ?

Techniquement parlant, il n'y a aucune raison pour que le module ne puisse pas communiquer directement avec le cœur de l'application maintenant, mais pour la plupart des expériences d'application, ce n'est toujours pas nécessaire. Puisque vous avez choisi cette architecture, vous devez respecter les règles définies par l'architecture.

J'ai compilé ce qui précède pour vous, j'espère que cela vous sera utile à l'avenir.

Articles associés :

Réponses détaillées aux événements en JS (tutoriel graphique)

Convertir un objet JSON en chaîne (détail les réponses au code sont jointes)

Bullage d'événement JS et capture d'événement (tutoriel graphique, violence simple)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn