ホームページ >ウェブフロントエンド >jsチュートリアル >js パブリッシュ/サブスクライバー モデルについての個人的な詳細な理解

js パブリッシュ/サブスクライバー モデルについての個人的な詳細な理解

大家讲道理
大家讲道理オリジナル
2017-04-11 10:39:401706ブラウズ

まず、書籍『JavaScript デザイン パターンと開発実践 //実際のパブリッシュとサブスクライブ モデル』から本文の紹介を抜粋します。
シャオ ミンは最近、ある家に恋をしました。営業所に到着して初めて、彼はその家がこの家にあると言いました。建物はすでに売り尽くされていた。幸いなことに、営業MMはXiao Mingに、近い将来に遅れて発売される予定であり、開発者が関連する手続きを行っており、手続きが完了したら購入できると伝えました。 しかし、それが正確にいつになるかは、まだ誰にもわかりません。そこでシャオミンさんは営業所の電話番号をメモし、毎日電話して購入時期かどうかを尋ねた。シャオ・ミンに加えて、シャオ・ホン、シャオ・チャン、シャオ・ロンもこの問題について毎日営業所に相談しています。 1 週間後、その営業担当者は毎日同じ内容の 1,000 件の電話に応答するのにうんざりし、退職を決意しました。

もちろん、現実にはそのような愚かな販売会社はありません。実際の話は次のとおりです。シャオミンは出発前に営業所に電話番号を残しました。セールスガールは、新しい物件が発売されたらすぐにシャオミンに通知するメッセージを送信すると約束した。シャオホン、シャオチャン、シャオロンも同様で、彼らの電話番号はすべて営業所の名簿に記録されており、新しい物件が発売されると、セールスガールは名簿を開いてそこにある電話番号を調べてテキストメッセージを送信します。一つ一つメッセージを送って知らせます。上の例では、SMS 通知の送信は典型的なパブリッシュ/サブスクライブ モデルであり、Xiao Ming や Xiao Hon などの購入者は購読者であり、家が売りに出されているというニュースを購読しています。発行者として、営業所は適切な時期に名簿に記載されている電話番号を調べ、順番に住宅購入者にニュースを発行します。

この例でパブリッシュ/サブスクライブ モデルを使用すると、明らかな利点があることがわかります。住宅購入者は、販売店に毎日電話して販売時期を問い合わせる必要はなくなり、販売店は発行者として、これらのメッセージ購読者に適切な時期に通知します。住宅購入者と営業所の間にはもはや強い結びつきはありません。新しい住宅購入者が現れても、営業所は携帯電話の番号を伝えるだけで済み、住宅購入者の状況を気にする必要はありません。住宅購入者が男性であっても、女性であっても、猿であっても。 また、営業 MM が退職し、営業所が 1 階から 2 階に移転したなど、営業所の変更は購入者には影響しません。オフィスはテキスト メッセージを忘れずに送信します。

まず、発行者として機能する人 (営業所など) を指定し、次にサブスクライバー (営業所名簿) に通知するコールバック関数を保存するキャッシュ リストを発行者に追加する必要があります。パブリッシャはこのキャッシュ リストを走査し、そこに格納されているサブスクライバ コールバック関数を順番にトリガーします (名簿を走査し、テキスト メッセージを 1 つずつ送信します)。さらに、コールバック関数にいくつかのパラメータを入力することもでき、サブスクライバはこれらのパラメータを受け取ることができます。これは非常に必要です。たとえば、営業所は、加入者に送信されるテキスト メッセージに住宅の単価、面積、容積率などの情報を追加できます。この情報を受信した後、加入者は独自の処理を実行できます。

<!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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。