Heim  >  Artikel  >  Web-Frontend  >  Eine ausführliche Erklärung des Beobachtermusters in Javascript (grafisches Tutorial)

Eine ausführliche Erklärung des Beobachtermusters in Javascript (grafisches Tutorial)

亚连
亚连Original
2018-05-19 11:38:291238Durchsuche

Das Beobachtermuster, auch bekannt als Publish-Subscribe-Muster, ist eines der am häufigsten verwendeten Entwurfsmuster. Der folgende Artikel gibt Ihnen hauptsächlich eine ausführliche Einführung in die relevanten Materialien des Beobachtermusters in Javascript.

Einführung

Das Beobachtermuster wird auch Publish/Subscribe-Muster (Publish/Subscribe) genannt. Es definiert eine Eins-zu-viele-Beziehung, die es mehreren Beobachterobjekten ermöglicht Gleichzeitig wird ein bestimmtes Themenobjekt überwacht. Wenn sich der Status dieses Themenobjekts ändert, werden alle Beobachterobjekte benachrichtigt, sodass sie sich automatisch aktualisieren können. Um ehrlich zu sein: Wenn wir keinen etwas Low-Level-Code schreiben würden, würden wir ihn möglicherweise nicht verwenden. Aber dadurch wird der Code flexibler und regelmäßiger, reduziert redundanter Code und erleichtert die Entwicklung von Modulen und Funktionen.

Vorteile der Verwendung des Beobachtermusters:

  1. Unterstützt einfache Broadcast-Kommunikation und benachrichtigt automatisch alle abonnierten Objekte.

  2. Nachdem die Seite geladen ist, kann das Zielobjekt problemlos eine dynamische Beziehung zum Beobachter haben, was die Flexibilität erhöht.

  3. Die abstrakte Kopplungsbeziehung zwischen dem Zielobjekt und dem Beobachter kann unabhängig erweitert und wiederverwendet werden.

Einführung von

Im Front-End-Geschäft sind benutzerdefinierte Ereignisse möglicherweise der am häufigsten genutzte Ort.
Tatsächlich befinden sich Browserereignisse auch im Beobachtermodus

p.onclick = function click() {
 console.log('click')
}

Hier abonniert die Funktion click das Klickereignis von p Wenn das Ereignis veröffentlicht wird, wird die entsprechende Funktion ausgeführt. Dieser Funktionsklick ist ein Beobachter.

Konkretes Verständnis

Tatsächlich können Sie es verstehen, indem Sie sich einfach die Code-Implementierung ansehen. Aber alles hängt auch von der Lebenserfahrung ab. Daher ist auch das konkrete Verständnis eine sehr wichtige Erfahrung.

Nehmen wir ein Beispiel eines Hochzeitsbanketts. Ein guter Freund von Ihnen heiratet zum Beispiel nicht jeden Tag, sondern nur ein- oder zweimal im Leben (vielleicht öfter). jeden Tag, aber nur zu bestimmten Zeiten. Ich kann ihn definitiv nicht jeden Tag fragen: „Heiratest du heute? Ich komme zum Bankett.“ Ein- oder zweimal ist in Ordnung, frag jeden Tag, jdn. Wenn Sie ein Single sind, der keinen Partner findet, und mich das jeden Tag fragen, werde ich Sie nicht töten. .

Dann muss hier eine Veranstaltung veröffentlicht werden, die Sie „benachrichtigen“ soll.

Als Beobachter habe ich die Veranstaltung seiner „Hochzeit“ abonniert. Wir sind gute Freunde und ich werde auf jeden Fall zu seiner Hochzeit gehen. Dann bin ich der Beobachter und „Ich gehe zur Hochzeit“ ist die entsprechende Handlung. Wenn ich die Veranstaltung „Hochzeit“ abonniere, muss ich ihn nicht jeden Tag fragen, was ich tun soll, Mädchen abholen, Abendessen ausmachen, Filme schauen, mich verabreden ... was auch immer.

Als er das Ereignis „Hochzeit“ veröffentlichte, wurde mir die Benachrichtigung zugesandt, und ich machte mich zu einem bestimmten Zeitpunkt an die Funktion „Am Hochzeitsbankett teilnehmen“...

//模拟代码
//我订阅了'marry' 事件
wo.on('marry',function(){
 //去参加婚礼酒席
})
//然后他发布。比如浏览器的点击
// 对应的我的 function就会执行

Entkopplung/Modul/Funktion

Tatsächlich ist im Code ein Vermittler ähnlich einem Zwischendienst erforderlich, um das Veröffentlichen und Abonnieren zu verwalten.

Zum Beispiel stellt der Event-Handler im Browser eine Abonnementschnittstelle bereit, empfängt dann das „Event“-Signal und veröffentlicht es für Sie. Lassen Sie den JS-Code Kontakt und Interaktion mit dem Browser haben. Aber ursprünglich waren es zwei verschiedene Dinge.

Meiner Meinung nach ist der größte Vorteil des Beobachtermusters die Entkopplung, die es uns ermöglicht, den Code in Funktionen und Module zu unterteilen, was ihn klarer macht, die Entwicklungskosten senkt und einfacher zu warten ist.

Zum Beispiel:

1. Für die Ansichtsanzeigeebene und die Modelllogikebene (Datenverarbeitung) in unserem Projekt schreiben wir zuerst die Seite, Ajax, String-Splicing und die Anforderung eine Schnittstelle. Bekämpfe es und gib es Dom. Möglicherweise haben wir eine js-Datei und eine Funktion, die eine Schnittstelle anfordert und für die Anzeige der Ansicht verantwortlich ist.

var xhr = new XMLHttpRequest ()
 xhr.open('get',url)
 xhr.onreadystatechange = function () {
 if(this.readyState !== 4) return
 if(this.status === 200) {
 ps.innerHTML = &#39;<p>&#39; + this.response + &#39;</p>&#39;
 //
 }
 }
 xhr.responseType = &#39;json&#39;
 xhr.send(null)

Tatsächlich sollte die Anfrage vom Display-Rendering getrennt werden.

//请求
function getData () {
 var xhr = new XMLHttpRequest ()
 xhr.open(&#39;get&#39;,url)
 xhr.onreadystatechange = function () {
 if(this.readyState !== 4) return
 if(this.status === 200) {
 this.emit(&#39;渲染&#39;)
 // 发布
 }
 }
 xhr.responseType = &#39;json&#39;
 xhr.send(null)
}
//渲染
function view () {}
xhr.on(&#39;渲染&#39;,view)

Es ist auch möglich, einen Rückruf direkt auf den Statuscode 200 zu setzen. Aber wenn ich zwei Renderfunktionen habe, die unterschiedliche Dinge verarbeiten, muss ich sie dann jedes Mal in andere Funktionen ändern? Muss ich den gleichen Anfragevorgang noch einmal schreiben?

Mit den Worten eines Beobachters

function view1 () {}
function view2 () {}
function view3 () {}
function view4 () {}
if(我要渲染view1) {
 xhr.on(&#39;渲染&#39;,view1) //订阅
 xhr.on(&#39;渲染&#39;,view2)
}else{
 xhr.on(&#39;渲染&#39;,view3)
 xhr.on(&#39;渲染&#39;,view4)
}

Der Vorteil ist, dass meine getData-Funktion, die Methode, nur für das Anfordern von Daten verantwortlich ist , und dann wird ihm eine Schnittstelle zur Verfügung gestellt, über die ich Methoden hinzufügen kann. Auf diese Weise ist mein getData ein relativ vollständiges Funktionsmodul, egal wie viele Situationen ich habe, der Code in meinem getData wird sich nicht ändern.

Manchmal ändern wir oft den Code, den wir zuvor geschrieben haben, um eine neue Funktion hinzuzufügen, um das Geschäft zu realisieren, was dazu führt, dass unsere ursprünglichen Funktionsmodule bis zur Unkenntlichkeit verändert werden.

Und es wird eine Menge doppelten Code geben.

Prozess? oder Modul?

Natürlich ist es sehr schwierig, ein gutes und vollständiges Funktionsmodul zu versiegeln, aber wir müssen zumindest einen Anfang haben.

Abonnieren Sie, um Methoden hinzuzufügen und diese auszuführen, wenn der Ereignispool veröffentlicht wird.

2. MV*-Klassenrahmen

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: &#39;INCREMENT&#39;};
document.addEventListener(&#39;click&#39;, function (e) {
 //触发一个Action
 store.dispatch(INCREASE_ACTION);
})

4、在node 中的作用 大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

实现一个可以发布订阅的类

&#39;use strict&#39;
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,&#39;aa-aa&#39;)
}
function b (something) {
 console.log(something)
}
 event.once(&#39;dosomething&#39;,a)
 event.emit(&#39;dosomething&#39;, &#39;chifan&#39;)
 //event.emit(&#39;dosomething&#39;)
// event.on(&#39;dosomething&#39;,a)
// event.on(&#39;dosomething&#39;,b)
// event.emit(&#39;dosomething&#39;,&#39;chifan&#39;)
// event.off(&#39;dosomething&#39;,a)
// setTimeout(() => {
// event.emit(&#39;dosomething&#39;,&#39;hejiu&#39;)
// },2000)

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JS DOM元素常见增删改查操作详解

JS刷新页面方法总结

JS callback回调函数使用案例详解

Das obige ist der detaillierte Inhalt vonEine ausführliche Erklärung des Beobachtermusters in Javascript (grafisches Tutorial). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn