Maison > Article > interface Web > Une explication approfondie du modèle d'observateur en Javascript (tutoriel graphique)
Le modèle d'observateur, également connu sous le nom de modèle de publication-abonnement, est l'un des modèles de conception les plus couramment utilisés. L'article suivant vous donne principalement une introduction approfondie aux matériaux pertinents du modèle d'observateur en Javascript.
Introduction
Le modèle d'observateur est également appelé modèle de publication/abonnement (Publish/Subscribe). Il définit une relation un-à-plusieurs, permettant à plusieurs objets observateurs de s'afficher. En même temps, un certain objet de sujet est surveillé Lorsque l'état de cet objet de sujet change, tous les objets observateurs seront avertis afin qu'ils puissent se mettre à jour automatiquement. Pour être honnête, si nous n’écrivions pas de code de bas niveau, nous ne l’utiliserions peut-être pas. Mais l’avoir rendra le code plus flexible et plus régulier, réduira le code redondant et facilitera le développement de modules et de fonctions.
Avantages de l'utilisation du modèle d'observateur :
Prend en charge la communication par diffusion simple et notifie automatiquement tous les objets abonnés.
Une fois la page chargée, l'objet cible peut facilement entretenir une relation dynamique avec l'observateur, augmentant ainsi la flexibilité.
La relation de couplage abstraite entre l'objet cible et l'observateur peut être étendue et réutilisée indépendamment.
Introduction de
Dans le domaine du front-end, l'endroit le plus couramment utilisé peut être les événements personnalisés.
En fait, les événements du navigateur sont également en mode observateur
p.onclick = function click() { console.log('click') }
Ici, la fonction click s'abonne à l'événement click de p. , Lorsqu'un événement est publié, la fonction correspondante sera exécutée. Cette fonction clic est un observateur.
Compréhension concrète
En fait, vous pouvez le comprendre simplement en regardant l'implémentation du code. Mais tout est lié. La conception de ces modèles de programmation vient aussi de l’expérience de la vie. La compréhension concrète est donc également une expérience très importante.
Prenons l’exemple d’un banquet de mariage. Par exemple, un de vos bons amis se marie. « Se marier » n'arrive pas tous les jours, cela n'arrive qu'une ou deux fois dans la vie (peut-être plus). Donc, notre « aller à son mariage » n'arrive certainement pas. tous les jours, mais seulement à certaines occasions. Je ne peux certainement pas lui demander tous les jours : « Est-ce que vous vous mariez aujourd'hui ? Je viendrai au banquet. Une ou deux fois, c'est bien, demande tous les jours, qn. Si vous êtes célibataire et que vous ne trouvez pas de partenaire et que vous lui demandez cela tous les jours, il ne vous tuera pas. .
Ensuite, il doit y avoir un événement publié ici, qui doit vous « avertir ».
En tant qu'observateur, je me suis abonné à l'événement de son "mariage". Nous sommes de bons amis et j'irai certainement à son mariage. Nous sommes déjà d'accord. Alors je suis l'observateur, et « je vais au mariage » est l'action correspondante. Lorsque je m'abonne à l'événement « Mariage », je n'ai pas besoin de lui demander tous les jours, que dois-je faire, draguer des filles, organiser des dîners, regarder des films, sortir avec quelqu'un... peu importe.
Quand il a posté l'événement 'mariage', la notification m'a été envoyée, et je suis allé faire la fonction 'assister au banquet de mariage' à une heure précise...
//模拟代码 //我订阅了'marry' 事件 wo.on('marry',function(){ //去参加婚礼酒席 }) //然后他发布。比如浏览器的点击 // 对应的我的 function就会执行
Découplage/Module/Fonction
En fait, dans le code, il faut un intermédiaire similaire à un service intermédiaire pour gérer la publication et s'abonner.
Par exemple, le gestionnaire d'événements dans le navigateur fournit une interface d'abonnement, puis reçoit le signal « événement » et vous le publie. Laissez le code js avoir un contact et une interaction avec le navigateur. Mais à l’origine, c’étaient deux choses différentes.
À mon avis, le plus grand avantage du modèle d'observateur est le découplage, qui nous permettra de séparer le code en fonctions et modules, le rendant plus clair, réduisant les coûts de développement et plus facile à maintenir.
Par exemple :
1. Pour la couche d'affichage de la vue et la couche logique du modèle (traitement des données) de notre projet, nous écrivons d'abord la page, l'ajax, l'épissage de chaîne et la requête. une interface. Combattez-le et donnez-le à dom. Peut-être avons-nous un fichier js et une fonction qui demande une interface et est responsable de l'affichage de la vue.
var xhr = new XMLHttpRequest () xhr.open('get',url) xhr.onreadystatechange = function () { if(this.readyState !== 4) return if(this.status === 200) { ps.innerHTML = '<p>' + this.response + '</p>' // } } xhr.responseType = 'json' xhr.send(null)
En fait, la requête doit être séparée du rendu d'affichage.
//请求 function getData () { var xhr = new XMLHttpRequest () xhr.open('get',url) xhr.onreadystatechange = function () { if(this.readyState !== 4) return if(this.status === 200) { this.emit('渲染') // 发布 } } xhr.responseType = 'json' xhr.send(null) } //渲染 function view () {} xhr.on('渲染',view)
Vous pouvez également le faire en plaçant un rappel directement sur le code d'état 200. Mais si j’ai deux fonctions de rendu qui gèrent des choses différentes, dois-je les remplacer par des fonctions différentes à chaque fois ? Dois-je réécrire le même processus de demande ?
Selon les mots d'un observateur
function view1 () {} function view2 () {} function view3 () {} function view4 () {} if(我要渲染view1) { xhr.on('渲染',view1) //订阅 xhr.on('渲染',view2) }else{ xhr.on('渲染',view3) xhr.on('渲染',view4) }
L'avantage réside dans ma fonction getData, la méthode n'est responsable que de demandant des données. Ensuite, il exposera une interface pour que j'ajoute des méthodes. De cette façon, mon getData est un module fonctionnel relativement complet, quel que soit le nombre de situations que je rencontre, le code de mon getData ne changera pas.
Parfois, nous modifions souvent le code que nous avons écrit auparavant afin d'ajouter une nouvelle fonction pour réaliser l'entreprise, ce qui entraîne une modification méconnaissable de nos modules fonctionnels d'origine.
Et il y aura beaucoup de code en double.
Processus ? ou un module ?
Bien sûr, il est très difficile de sceller un module fonctionnel bon et complet, mais il faut au moins avoir un début.
Abonnez-vous pour ajouter des méthodes et exécutez-les lorsque le pool d'événements est publié.
2. Cadre de classe MV*
MVC也是一种设计模式,这里面也都应用了观察者。
他内部也都是各种发布订阅,好像是一个观察者模型,从而实现了一个模拟的内存中的dom改变,计算出那个DOM节点应该改变。当然具体实现要做好多事情…就不…
3、redux
简单实现一个createstore函数
//这是一个工厂函数,可以创建store const createStore = (reducer) => { let state; // 定义存储的state let listeners = []; // getState的作用很简单就是返回当前是state const getState = ()=> state; //定义一个派发函数 //当在外界调用此函数的时候,会修改状态 const dispatch = (action)=>{ //调用reducer函数修改状态,返回一新的状态并赋值给这个局部状态变量 state = reducer(state,action); //依次调用监听函数,通知所有的监听函数 listeners.forEach(listener => listener()); } //订阅此状态的函数,当状态发生变化的时候记得调用此监听函数 const subscribe = function(listener){ //先把此监听 加到数组中 listeners.push(listener); //返回一个函数,当调用它的时候将此监听函数从监听数组移除 return function(){ listeners = listeners.filter(l => l != listener); } } //默认调用一次dispatch给state赋一个初始值 dispatch(); return { getState, dispatch, subscribe } } let store = createStore(reducer); //把数据渲染到界面上 const render = () => { document.body.innerText = store.getState(); } // 订阅状态变化事件,当状态变化时用监听函数 store.subscribe(render); render(); var INCREASE_ACTION = {type: 'INCREMENT'}; document.addEventListener('click', function (e) { //触发一个Action store.dispatch(INCREASE_ACTION); })
4、在node 中的作用 大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
实现一个可以发布订阅的类
'use strict' class EmitterEvent { constructor() { //构造器。实例上创建一个事件池 this._event = {} } //on 订阅 on (eventName, handler) { // 根据eventName,事件池有对应的事件数组, 就push添加,没有就新建一个。 // 严谨一点应该判断handler的类型,是不是function if(this._event[eventName]) { this._event[eventName].push(handler) } else { this._event[eventName] = [handler] } } emit (eventName) { // 根据eventName找到对应数组 var events = this._event[eventName]; // 取一下传进来的参数,方便给执行的函数 var otherArgs = Array.prototype.slice.call(arguments,1) var that = this if(events) { events.forEach((event) => { event.apply(that, otherArgs) }) } } // 解除订阅 off (eventName, handler) { var events = this._event[eventName] if(events) { this._event[eventName] = events.filter((event) => { return event !== handler }) } } // 订阅以后,emit 发布执行一次后自动解除订阅 once (eventName, handler) { var that = this function func () { var args = Array.prototype.slice.call(arguments,0) handler.apply(that, args) this.off(eventName,func) } this.on(eventName, func) } } var event = new EmitterEvent() function a (something) { console.log(something,'aa-aa') } function b (something) { console.log(something) } event.once('dosomething',a) event.emit('dosomething', 'chifan') //event.emit('dosomething') // event.on('dosomething',a) // event.on('dosomething',b) // event.emit('dosomething','chifan') // event.off('dosomething',a) // setTimeout(() => { // event.emit('dosomething','hejiu') // },2000)
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
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!