>  기사  >  웹 프론트엔드  >  js 게시-구독자 모델에 대한 자세한 개인적 이해

js 게시-구독자 모델에 대한 자세한 개인적 이해

大家讲道理
大家讲道理원래의
2017-04-11 10:39:401684검색

먼저 JavaScript Design Patterns and Development Practices//Publish and Subscribe Model in Reality
Xiao Ming은 최근 한 집과 사랑에 빠졌고, 도착 후 이야기를 들었습니다. 판매 사무실, 이 개발 지역의 주택은 이미 매진되었습니다. 다행스럽게도 영업 MM은 샤오밍에게 가까운 시일 내에 출시가 늦어질 것이며 개발자가 관련 절차를 밟고 있으며 절차가 완료되면 구매할 수 있다고 말했습니다. 그러나 그것이 정확히 언제일지는 아직 아무도 알 수 없습니다. 그래서 샤오밍은 영업소의 전화번호를 적어두고 매일 그에게 전화를 걸어 살 때가 되었는지 물어보곤 했습니다. Xiao Ming 외에도 Xiao Hong, Xiao Qiang 및 Xiao Long도 매일 이 문제에 대해 영업소에 문의합니다. 일주일 후, 영업사원은 매일 같은 내용으로 1,000통의 전화를 받는 것이 지겨워서 사직을 결정했습니다.

물론 현실에는 이런 멍청한 판매회사가 없습니다. 실제 이야기는 샤오밍이 떠나기 전에 판매점에 전화번호를 남겼다는 것입니다. 판매원은 새 부동산이 출시되자마자 Xiao Ming에게 알리는 메시지를 보내겠다고 그에게 약속했습니다. Xiaohong, Xiaoqiang 및 Xiaolong도 마찬가지입니다. 그들의 전화번호는 모두 판매 사무소 명단에 기록되어 있습니다. 새 부동산이 출시되면 판매원은 명단을 열고 거기에 있는 전화번호를 확인하고 문자를 보냅니다. 메시지를 하나씩 알려주세요. 위의 예에서 SMS 알림을 보내는 것은 일반적인 게시-구독 모델입니다. Xiao Ming 및 Xiao Hong과 같은 구매자는 구독자이며 집이 매물로 나왔다는 뉴스를 구독했습니다. 발행인으로서 판매 사무소는 적절한 시간에 명단에 있는 전화번호를 검토하고 주택 구매자에게 차례로 뉴스를 게시합니다. ​

이 예에서 게시-구독 모델을 사용하면 분명한 이점이 있음을 알 수 있습니다. 주택 구매자는 더 이상 판매 시간을 문의하기 위해 판매 사무소에 매일 전화할 필요가 없습니다. 판매 사무소는 게시자로서 이러한 메시지 가입자에게 알립니다. 주택 구매자와 판매 사무소 사이에는 더 이상 강력한 연결이 없습니다. 새로운 주택 구매자가 나타나면 판매 사무소에 휴대폰 번호만 남겨두면 주택 구매자의 어떤 상황에도 관심이 없습니다. 주택 구매자가 남자인지, 여자인지, 아니면 원숭이인지에 관계없이요. 그리고 판매 사무소의 변경 사항은 구매자에게 영향을 미치지 않습니다. 예를 들어 판매 MM이 사임하고 판매 사무소가 1층에서 2층으로 이동하는 경우 이러한 변경은 판매와 관련이 없습니다. 사무실에서는 문자 메시지를 보내는 것을 기억합니다.

먼저 게시자 역할을 할 사람(예: 영업소)을 지정한 다음 게시자에 캐시 목록을 추가하여 구독자에게 알리는 콜백 기능(판매소 명단)을 저장합니다. 메시지를 받으면 게시자는 이 캐시 목록을 순회하고 여기에 저장된 구독자 콜백 기능을 차례로 트리거합니다(명단을 순회하고 문자 메시지를 하나씩 보냅니다). 또한 콜백 함수에 일부 매개변수를 입력할 수도 있으며 구독자는 이러한 매개변수를 수신할 수 있습니다. 예를 들어 판매 사무소에서는 구독자에게 전송되는 문자 메시지에 해당 주택의 단가, 면적, 용적률 및 기타 정보를 추가할 수 있습니다.

  • <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>观察者模式</title>
    </head>
    <body>
    <button id="count">点我</button>
    <p id="show"></p>
    <script>
        //我的个人理解
        //发布者首先需要一个对象来保存事件的回调函数,这个对象的属性就是事件类型,比如{"click":[fn1,fn2],"mouseover":[fn3,fn4]}
        //订阅事件:首先要判断这个事件类型是否存在当前的对象上,如果不存在那就初始化一下就是添加这个属性,并且给这个属性的值设置为空数组
        //如果已经存在了那么久开始把该对调函数push进去对应的属性的值, 该值为一个数组
        //发布事件:发布事件就要一个个的通知订阅者,还有就是你发布了什么事件。这里要有if判断,
        // 先从参数中取出要发布事件的key,然后获取到key对应的回调函数数组,取出数组后先判断数组是否存在或者数组长度是否为0,如果不存在或者为0
        //就结束程序,若上述条件不成立就执行for循环,一次遍历回调函数数组,并执行里面的函数,这里需要改变回调函数的this指向。防止丢之
        //this。
        //移出事件:先判断要移出的key的值是否为空,若空则退出程序否则再判断是否传入了要移出哪个回调函数,若空,则认为要移出全部的函数,就把数组长度设置为0
        //
      //下面是js设计模式与开发实践上的实现过程
        var Event=(function(){
                var clientList={},
                    listen,
                    trigger,
                    remove;
            listen=function(key,fn){
                if(!clientList[key]){
                    clientList[key]=[];
                }
                clientList[key].push(fn);
            };
            trigger=function(){
                var key=Array.prototype.shift.call(arguments),
                    cb=clientList[key];
                if(!cb||cb.length==0){
                    return false;//如果没有保存回调函数就退出程序
                }
                for(var i=0;i<cb.length;i++ ){
                    cb[i].apply(this,arguments);//为什么要用applly呢,这是为了把触发时传入的参数传入给cb[i]对应的回调函数里面使用并且还要改变this指向
                }
            };
            remove=function (key,fn) {
    
                var cb=clientList[key];
                if(!cb){
                    return false;//如果要移除的key的值为空就代表没有人订阅该key和设置回调函数则直接返回
                }
                if(!fn){//如果没有传入具体的回调函数,表示需要取消key对应的消息的所有订阅
                    cb&&(cb.length=0);//这里cb是已经存在了就把cb的length设置为0.我有疑问,到这里其实cb不会不存在了吧上面如果不存在就退出了如何会走到这一步?
                }
                else{
                    for(var l=0;l<cb.length;l++){
                        var _cb=cb[l];
                        if(_cb===fn){//寻找哪个和要删除的回调函数一样
                            cb.splice(l,1);//从l处删除一个元素
                        }
                    }
                }
            };
            return {
                listen:listen,
                trigger:trigger,
                remove:remove
            }//这里返回这个对象其实是相当于中介代理的意思,请看下面的实际例子解释:
    //我们给每个发布者对象都添加了listen 和trigger 方法,以及一个缓存列表clientList,
    //这其实是一种资源浪费。
    //小明跟售楼处对象还是存在一定的耦合性,小明至少要知道售楼处对象的名字是
    //才能顺利的订阅到事件。
    //因此返回一个通用的对象,不必知道这个对象的名字,只需要把这个对象的一个引用给一个变量就行了
        })();
        Event.listen("A",fn1=function(data){
            console.log(data);
        })
        Event.listen("A",fn2=function(data){
            console.log(data);
        })
        Event.remove("A",fn1);
        Event.trigger("A","猴赛雷啊");
    </script>
    <script>
        var a=(function(){
            var count=0;
            var btn=document.getElementById(&#39;count&#39;);
            btn.onclick=function () {
                Event.trigger(&#39;add&#39;,count++);
            }
        })();
        var b=(function () {
            var p=document.getElementById(&#39;show&#39;);
            Event.listen(&#39;add&#39;,function(data){
                p.innerHTML=data;
            })
        })();
    </script>
    </body>
    </html>
마지막으로 저자는 발행-구독 모델의 단점도 설명했습니다.
커뮤니케이션에 글로벌 발행-구독 모델을 너무 많이 사용하는 경우 모듈 사이, 그러면 모듈 사이의 연결이 보이지 않게 숨겨집니다. 우리는 결국 어느 모듈에서 메시지가 왔는지, 어느 모듈로 메시지가 흘러갈지 알 수 없게 될 것이며, 이로 인해 유지 관리에 약간의 문제가 발생할 수 있습니다. 어쩌면 특정 모듈의 역할은 일부 인터페이스 다른 모듈을 호출하려면 .

위 내용은 js 게시-구독자 모델에 대한 자세한 개인적 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.