Tại sao người ta lại sử dụng mẫu Đăng ký / Đăng ký (trong JS / jQuery)?


103

Vì vậy, một đồng nghiệp đã giới thiệu cho tôi mẫu xuất bản / đăng ký (trong JS / jQuery), nhưng tôi đang gặp khó khăn khi hiểu tại sao một người lại sử dụng mẫu này thay vì JavaScript / jQuery 'bình thường'.

Ví dụ: trước đây tôi có mã sau ...

$container.on('click', '.remove_order', function(event) {
    event.preventDefault();
    var orders = $(this).parents('form:first').find('div.order');
    if (orders.length > 2) {
        orders.last().remove();
    }
});

Và thay vào đó, tôi có thể thấy công lao của việc làm này ...

removeOrder = function(orders) {
    if (orders.length > 2) {
        orders.last().remove();
    }
}

$container.on('click', '.remove_order', function(event) {
    event.preventDefault();
    removeOrder($(this).parents('form:first').find('div.order'));
});

Bởi vì nó giới thiệu khả năng sử dụng lại removeOrderchức năng cho các sự kiện khác nhau, v.v.

Nhưng tại sao bạn quyết định triển khai mô hình xuất bản / đăng ký và đi đến các độ dài sau, nếu nó làm điều tương tự? (FYI, tôi đã sử dụng jQuery tiny pub / sub )

removeOrder = function(e, orders) {
    if (orders.length > 2) {
        orders.last().remove();
    }
}

$.subscribe('iquery/action/remove-order', removeOrder);

$container.on('click', '.remove_order', function(event) {
    event.preventDefault();
    $.publish('iquery/action/remove-order', $(this).parents('form:first').find('div.order'));
});

Tôi chắc chắn đã đọc về mô hình này, nhưng tôi không thể tưởng tượng được tại sao điều này lại cần thiết. Các hướng dẫn tôi đã xem giải thích cách triển khai mô hình này chỉ bao gồm các ví dụ cơ bản như của riêng tôi.

Tôi tưởng tượng rằng tính hữu dụng của pub / sub sẽ tự rõ ràng trong một ứng dụng phức tạp hơn, nhưng tôi không thể tưởng tượng được. Tôi sợ rằng tôi hoàn toàn thiếu điểm; nhưng tôi muốn biết điểm nếu có!

Bạn có thể giải thích ngắn gọn lý do tại sao và trong những trường hợp nào thì mô hình này lại có lợi? Có đáng sử dụng mô hình pub / sub cho các đoạn mã như các ví dụ của tôi ở trên không?

Câu trả lời:


222

Đó là tất cả về khớp nối lỏng lẻo và trách nhiệm duy nhất, đi đôi với các mẫu MV * (MVC / MVP / MVVM) trong JavaScript rất hiện đại trong vài năm qua.

Khớp nối lỏng lẻo là một nguyên tắc hướng đối tượng, trong đó mỗi thành phần của hệ thống biết trách nhiệm của mình và không quan tâm đến các thành phần khác (hoặc ít nhất cố gắng không quan tâm đến chúng nhiều nhất có thể). Khớp nối lỏng lẻo là một điều tốt vì bạn có thể dễ dàng sử dụng lại các mô-đun khác nhau. Bạn không kết hợp với các giao diện của các mô-đun khác. Sử dụng xuất bản / đăng ký, bạn chỉ được kết hợp với giao diện xuất bản / đăng ký, đây không phải là vấn đề lớn - chỉ là hai phương pháp. Vì vậy, nếu bạn quyết định sử dụng lại một mô-đun trong một dự án khác, bạn có thể sao chép và dán nó và nó có thể hoạt động hoặc ít nhất bạn sẽ không cần nhiều nỗ lực để làm cho nó hoạt động.

Khi nói về khớp nối lỏng, chúng ta nên đề cập đến tách biệt của mối quan tâm. Nếu bạn đang tạo ứng dụng bằng cách sử dụng mẫu kiến ​​trúc MV *, bạn luôn có (các) Mô hình và (các) Chế độ xem. Mô hình là phần kinh doanh của ứng dụng. Bạn có thể sử dụng lại nó trong các ứng dụng khác nhau, vì vậy không nên kết hợp nó với Chế độ xem của một ứng dụng, nơi bạn muốn hiển thị nó, bởi vì thông thường trong các ứng dụng khác nhau, bạn có các chế độ xem khác nhau. Vì vậy, bạn nên sử dụng xuất bản / đăng ký cho giao tiếp Model-View. Khi Mô hình của bạn thay đổi, nó xuất bản một sự kiện, Chế độ xem sẽ nắm bắt và cập nhật chính nó. Bạn không có bất kỳ chi phí nào từ việc xuất bản / đăng ký, nó sẽ giúp bạn trong việc tách. Theo cách tương tự, bạn có thể giữ logic ứng dụng của mình trong Bộ điều khiển chẳng hạn (MVVM, MVP nó không chính xác là Bộ điều khiển) và giữ Chế độ xem đơn giản nhất có thể. Khi Chế độ xem của bạn thay đổi (hoặc người dùng nhấp vào thứ gì đó chẳng hạn) nó chỉ xuất bản một sự kiện mới, Bộ điều khiển sẽ nắm bắt và quyết định phải làm gì. Nếu bạn quen thuộc vớiMẫu MVC hoặc với MVVM trong các công nghệ của Microsoft (WPF / Silverlight), bạn có thể nghĩ đến việc xuất bản / đăng ký giống như mẫu Observer . Cách tiếp cận này được sử dụng trong các framework như Backbone.js, Knockout.js (MVVM).

Đây là một ví dụ:

//Model
function Book(name, isbn) {
    this.name = name;
    this.isbn = isbn;
}

function BookCollection(books) {
    this.books = books;
}

BookCollection.prototype.addBook = function (book) {
    this.books.push(book);
    $.publish('book-added', book);
    return book;
}

BookCollection.prototype.removeBook = function (book) {
   var removed;
   if (typeof book === 'number') {
       removed = this.books.splice(book, 1);
   }
   for (var i = 0; i < this.books.length; i += 1) {
      if (this.books[i] === book) {
          removed = this.books.splice(i, 1);
      }
   }
   $.publish('book-removed', removed);
   return removed;
}

//View
var BookListView = (function () {

   function removeBook(book) {
      $('#' + book.isbn).remove();
   }

   function addBook(book) {
      $('#bookList').append('<div id="' + book.isbn + '">' + book.name + '</div>');
   }

   return {
      init: function () {
         $.subscribe('book-removed', removeBook);
         $.subscribe('book-aded', addBook);
      }
   }
}());

Một vi dụ khac. Nếu bạn không thích cách tiếp cận MV *, bạn có thể sử dụng một cái gì đó khác một chút (có sự giao nhau giữa cách mà tôi sẽ mô tả tiếp theo và cách được đề cập cuối cùng). Chỉ cần cấu trúc ứng dụng của bạn trong các mô-đun khác nhau. Ví dụ, hãy nhìn vào Twitter.

Mô-đun Twitter

Nếu bạn nhìn vào giao diện, bạn chỉ đơn giản là có các hộp khác nhau. Bạn có thể coi mỗi hộp như một mô-đun khác nhau. Ví dụ, bạn có thể đăng một tweet. Hành động này yêu cầu cập nhật một vài mô-đun. Đầu tiên nó phải cập nhật dữ liệu hồ sơ của bạn (hộp trên bên trái) nhưng nó cũng phải cập nhật dòng thời gian của bạn. Tất nhiên, bạn có thể giữ các tham chiếu đến cả hai mô-đun và cập nhật chúng một cách riêng biệt bằng giao diện công khai của chúng nhưng sẽ dễ dàng hơn (và tốt hơn) nếu chỉ xuất bản một sự kiện. Điều này sẽ làm cho việc sửa đổi ứng dụng của bạn dễ dàng hơn vì khớp nối lỏng hơn. Nếu bạn phát triển mô-đun mới phụ thuộc vào các tweet mới, bạn chỉ có thể đăng ký sự kiện “xuất bản-tweet” và xử lý nó. Cách tiếp cận này rất hữu ích và có thể làm cho ứng dụng của bạn được tách biệt rất tốt. Bạn có thể sử dụng lại các mô-đun của mình rất dễ dàng.

Đây là một ví dụ cơ bản về cách tiếp cận cuối cùng (đây không phải là mã twitter ban đầu mà nó chỉ là một mẫu của tôi):

var Twitter.Timeline = (function () {
   var tweets = [];
   function publishTweet(tweet) {
      tweets.push(tweet);
      //publishing the tweet
   };
   return {
      init: function () {
         $.subscribe('tweet-posted', function (data) {
             publishTweet(data);
         });
      }
   };
}());


var Twitter.TweetPoster = (function () {
   return {
       init: function () {
           $('#postTweet').bind('click', function () {
               var tweet = $('#tweetInput').val();
               $.publish('tweet-posted', tweet);
           });
       }
   };
}());

Đối với cách tiếp cận này, có một bài nói chuyện tuyệt vời của Nicholas Zakas . Đối với MV *, các bài báo và sách hay nhất mà tôi biết được xuất bản bởi Addy Osmani .

Hạn chế: Bạn phải cẩn thận về việc sử dụng quá nhiều xuất bản / đăng ký. Nếu bạn có hàng trăm sự kiện thì việc quản lý tất cả chúng có thể trở nên rất khó hiểu. Bạn cũng có thể có va chạm nếu bạn không sử dụng không gian tên (hoặc sử dụng không đúng cách). Bạn có thể tìm thấy cách triển khai nâng cao của Mediator trông giống như một bản xuất bản / đăng ký tại đây https://github.com/ajacksified/Mediator.js . Nó có không gian tên và các tính năng như sự kiện “sôi sục”, tất nhiên, có thể bị gián đoạn. Một nhược điểm khác của việc xuất bản / đăng ký là kiểm thử đơn vị cứng, có thể khó tách các chức năng khác nhau trong các mô-đun và kiểm tra chúng một cách độc lập.


3
Cảm ơn bạn, điều đó có ý nghĩa. Tôi đã quen với mẫu MVC vì tôi sử dụng nó mọi lúc với PHP, nhưng tôi chưa nghĩ về nó về lập trình hướng sự kiện. :)
Maccath

2
Cảm ơn cho mô tả này. Thực sự đã giúp tôi xoay quanh khái niệm này.
flybear

1
Đó là một câu trả lời tuyệt vời. Không thể ngăn bản thân mình bỏ phiếu cho điều này :)
Naveed Butt

1
Giải thích tuyệt vời, nhiều ví dụ, đề xuất đọc thêm. A ++.
Carson

16

Mục tiêu chính là giảm sự ghép nối giữa các mã. Đó là một lối suy nghĩ hơi dựa trên sự kiện, nhưng "sự kiện" không gắn với một đối tượng cụ thể.

Tôi sẽ viết ra một ví dụ lớn bên dưới bằng một số mã giả trông giống như JavaScript.

Giả sử chúng ta có một Radio lớp học và một lớp Tiếp sóng:

class Relay {
    function RelaySignal(signal) {
        //do something we don't care about right now
    }
}

class Radio {
    function ReceiveSignal(signal) {
        //how do I send this signal to other relays?
    }
}

Bất cứ khi nào đài phát thanh nhận được tín hiệu, chúng tôi muốn một số rơ le chuyển tiếp thông điệp theo một cách nào đó. Số lượng và loại rơ le có thể khác nhau. Chúng tôi có thể làm như thế này:

class Radio {
    var relayList = [];

    function AddRelay(relay) {
        relayList.add(relay);
    }

    function ReceiveSignal(signal) {
        for(relay in relayList) {
            relay.Relay(signal);
        }
    }

}

Điều này hoạt động tốt. Nhưng bây giờ hãy tưởng tượng chúng ta muốn một thành phần khác cũng tham gia các tín hiệu mà lớp Radio nhận được, đó là Loa:

(xin lỗi nếu các phép loại suy không phải là hàng đầu ...)

class Speakers {
    function PlaySignal(signal) {
        //do something with the signal to create sounds
    }
}

Chúng tôi có thể lặp lại mô hình một lần nữa:

class Radio {
    var relayList = [];
    var speakerList = [];

    function AddRelay(relay) {
        relayList.add(relay);
    }

    function AddSpeaker(speaker) {
        speakerList.add(speaker)
    }

    function ReceiveSignal(signal) {

        for(relay in relayList) {
            relay.Relay(signal);
        }

        for(speaker in speakerList) {
            speaker.PlaySignal(signal);
        }

    }

}

Chúng tôi có thể làm cho điều này tốt hơn nữa bằng cách tạo một giao diện, như "SignalListener", để chúng tôi chỉ cần một danh sách trong lớp Radio và luôn có thể gọi cùng một hàm trên bất kỳ đối tượng nào chúng tôi muốn nghe tín hiệu. Nhưng điều đó vẫn tạo ra sự kết hợp giữa bất kỳ giao diện / lớp cơ sở / vv nào mà chúng ta quyết định và lớp Radio. Về cơ bản, bất cứ khi nào bạn thay đổi một trong các lớp Radio, Signal hoặc Relay, bạn phải nghĩ xem nó có thể ảnh hưởng như thế nào đến hai lớp kia.

Bây giờ chúng ta hãy thử một cái gì đó khác nhau. Hãy tạo một lớp thứ tư có tên là RadioMast:

class RadioMast {

    var receivers = [];

    //this is the "subscribe"
    function RegisterReceivers(signaltype, receiverMethod) {
        //if no list for this type of signal exits, create it
        if(receivers[signaltype] == null) {
            receivers[signaltype] = [];
        }
        //add a subscriber to this signal type
        receivers[signaltype].add(receiverMethod);
    }

    //this is the "publish"
    function Broadcast(signaltype, signal) {
        //loop through all receivers for this type of signal
        //and call them with the signal
        for(receiverMethod in receivers[signaltype]) {
            receiverMethod(signal);
        }
    }
}

Bây giờ chúng ta có một mẫu mà chúng ta biết và chúng ta có thể sử dụng nó cho bất kỳ số lượng và kiểu lớp nào miễn là chúng:

  • biết về RadioMast (lớp xử lý tất cả các tin nhắn đi qua)
  • biết về chữ ký phương thức để gửi / nhận tin nhắn

Vì vậy, chúng tôi thay đổi lớp Radio thành dạng cuối cùng, đơn giản của nó:

class Radio {
    function ReceiveSignal(signal) {
        RadioMast.Broadcast("specialradiosignal", signal);
    }
}

Và chúng tôi thêm loa và bộ chuyển tiếp vào danh sách bộ thu của RadioMast cho loại tín hiệu này:

RadioMast.RegisterReceivers("specialradiosignal", speakers.PlaySignal);
RadioMast.RegisterReceivers("specialradiosignal", relay.RelaySignal);

Giờ đây, lớp Speakers và Relay không có kiến ​​thức về bất cứ điều gì ngoại trừ việc chúng có một phương thức có thể nhận tín hiệu và lớp Radio, là nhà xuất bản, biết về RadioMast mà nó phát tín hiệu. Đây là điểm của việc sử dụng hệ thống truyền thông báo như xuất bản / đăng ký.


Thực sự tuyệt vời khi có một ví dụ cụ thể cho thấy cách triển khai pub / sub pattern có thể tốt hơn so với việc sử dụng các phương pháp 'bình thường'! Cảm ơn bạn!
Maccath

1
Không có gì! Cá nhân tôi thường thấy rằng bộ não của tôi không 'nhấp chuột' khi nói đến các mô hình / phương pháp luận mới cho đến khi tôi nhận ra một vấn đề thực tế mà nó giải quyết cho tôi. Mô hình phụ / quán rượu là tuyệt vời với các kiến ​​trúc được kết hợp chặt chẽ về mặt khái niệm nhưng chúng tôi vẫn muốn giữ chúng tách biệt nhiều nhất có thể. Hãy tưởng tượng một trò chơi, nơi bạn có hàng trăm đối tượng mà tất cả đều có phản ứng với những điều xảy ra xung quanh họ ví dụ, và các đối tượng này có thể được tất cả mọi thứ: máy nghe nhạc, đạn, cây, hình học, gui vv vv
Anders Arpi

3
JavaScript không có classtừ khóa. Vui lòng nhấn mạnh thực tế này, ví dụ. bằng cách phân loại mã của bạn là mã giả.
Rob W

Thực tế trong ES6 có một từ khóa lớp.
Minko Gechev

5

Các câu trả lời khác đã làm rất tốt trong việc chỉ ra cách thức hoạt động của mẫu. Tôi muốn giải quyết câu hỏi ngụ ý " cách làm cũ có gì sai? " Vì tôi đã làm việc với mô hình này gần đây và tôi thấy nó liên quan đến sự thay đổi trong suy nghĩ của tôi.

Hãy tưởng tượng chúng ta đã đăng ký một bản tin kinh tế. Bản tin xuất bản với tiêu đề: " Hạ chỉ số Dow Jones xuống 200 điểm ". Đó sẽ là một thông điệp kỳ quặc và hơi vô trách nhiệm để gửi đi. Tuy nhiên, nếu nó xuất bản: " Enron đã nộp đơn bảo vệ phá sản chương 11 vào sáng nay ", thì đây là một thông điệp hữu ích hơn. Lưu ý rằng thông báo có thể khiến Dow Jones giảm 200 điểm, nhưng đó là một vấn đề khác.

Có một sự khác biệt giữa việc gửi một lệnh và thông báo về một điều gì đó vừa xảy ra. Với ý nghĩ này, hãy sử dụng phiên bản gốc của mẫu pub / sub, bỏ qua trình xử lý ngay bây giờ:

$.subscribe('iquery/action/remove-order', removeOrder);

$container.on('click', '.remove_order', function(event) {
    event.preventDefault();
    $.publish('iquery/action/remove-order', $(this).parents('form:first').find('div.order'));
});

Đã có một sự kết hợp chặt chẽ ngụ ý ở đây, giữa hành động của người dùng (một nhấp chuột) và phản hồi của hệ thống (một đơn đặt hàng đang bị xóa). Hiệu quả trong ví dụ của bạn, hành động là đưa ra một lệnh. Hãy xem xét phiên bản này:

$.subscribe('iquery/action/remove-order-requested', handleRemoveOrderRequest);

$container.on('click', '.remove_order', function(event) {
    event.preventDefault();
    $.publish('iquery/action/remove-order-requested', $(this).parents('form:first').find('div.order'));
});

Bây giờ trình xử lý đang phản hồi điều gì đó quan tâm đã xảy ra, nhưng không có nghĩa vụ xóa đơn đặt hàng. Trên thực tế, trình xử lý có thể thực hiện tất cả những việc không liên quan trực tiếp đến việc xóa đơn đặt hàng, nhưng vẫn có thể liên quan đến hành động gọi. Ví dụ:

handleRemoveOrderRequest = function(e, orders) {
    logAction(e, "remove order requested");
    if( !isUserLoggedIn()) {
        adviseUser("You need to be logged in to remove orders");
    } else if (isOkToRemoveOrders(orders)) {
        orders.last().remove();
        adviseUser("Your last order has been removed");
        logAction(e, "order removed OK");
    } else {
        adviseUser("Your order was not removed");
        logAction(e, "order not removed");
    }
    remindUserToFloss();
    increaseProgrammerBrowniePoints();
    //etc...
}

Sự khác biệt giữa một lệnh và một thông báo là một sự khác biệt hữu ích đối với mẫu này, IMO.


nếu 2 chức năng ( remindUserToFloss& increaseProgrammerBrowniePoints) cuối cùng của bạn được đặt trong các mô-đun riêng biệt, bạn sẽ xuất bản 2 sự kiện lần lượt ngay sau nhau ngay tại đó handleRemoveOrderRequesthay bạn sẽ flossModulexuất bản một sự kiện lên một browniePointsmô-đun khi remindUserToFloss()hoàn tất?
Bryan P

4

Vì vậy, bạn không cần phải gọi phương thức / hàm hardcode, bạn chỉ cần xuất bản sự kiện mà không cần quan tâm ai sẽ lắng nghe. Điều này làm cho nhà xuất bản độc lập với người đăng ký, giảm sự phụ thuộc (hoặc ghép nối, bất kỳ thuật ngữ nào bạn thích) giữa 2 phần khác nhau của ứng dụng.

Dưới đây là một số nhược điểm của khớp nối như wikipedia đã đề cập

Các hệ thống được kết hợp chặt chẽ có xu hướng thể hiện các đặc điểm phát triển sau đây, thường được coi là nhược điểm:

  1. Một thay đổi trong một mô-đun thường tạo ra hiệu ứng gợn sóng thay đổi trong các mô-đun khác.
  2. Việc lắp ráp các mô-đun có thể đòi hỏi nhiều nỗ lực và / hoặc thời gian hơn do sự phụ thuộc giữa các mô-đun tăng lên.
  3. Một mô-đun cụ thể có thể khó sử dụng lại và / hoặc kiểm tra hơn vì các mô-đun phụ thuộc phải được đưa vào.

Hãy coi một thứ giống như một đối tượng đóng gói dữ liệu kinh doanh. Nó có lệnh gọi phương thức được mã hóa cứng để cập nhật trang bất cứ khi nào tuổi được đặt:

var person = {
    name: "John",
    age: 23,

    setAge: function( age ) {
        this.age = age;
        showAge( age );
    }
};

//Different module

function showAge( age ) {
    $("#age").text( age );
}

Bây giờ tôi không thể kiểm tra đối tượng người mà không bao gồm showAgechức năng. Ngoài ra, nếu tôi cũng cần hiển thị độ tuổi trong một số mô-đun GUI khác, tôi cần mã hóa lệnh gọi phương thức đó vào .setAgevà bây giờ có các phụ thuộc cho 2 mô-đun không liên quan trong đối tượng người. Cũng khó duy trì khi bạn thấy những cuộc gọi đó được thực hiện và chúng thậm chí không nằm trong cùng một tệp.

Lưu ý rằng bên trong cùng một mô-đun, tất nhiên bạn có thể có các cuộc gọi phương thức trực tiếp. Nhưng dữ liệu kinh doanh và hành vi gui hời hợt không nên nằm trong cùng một mô-đun theo bất kỳ tiêu chuẩn hợp lý nào.


Tôi không hiểu khái niệm 'phụ thuộc' ở đây; phần phụ thuộc trong ví dụ thứ hai của tôi ở đâu và nó bị thiếu ở đâu trong ví dụ thứ ba? Tôi không thể thấy bất kỳ sự khác biệt thực tế nào giữa đoạn mã thứ hai và thứ ba - dường như nó chỉ thêm một 'lớp' mới giữa hàm và sự kiện mà không có lý do thực sự. Tôi có lẽ đang bị mù, nhưng tôi nghĩ tôi cần nhiều người chỉ dẫn hơn. :(
Maccath 22/11/12

1
Bạn có thể cung cấp một trường hợp sử dụng mẫu trong đó việc xuất bản / đăng ký sẽ phù hợp hơn là chỉ tạo một chức năng thực hiện cùng một việc không?
Jeffrey Sweeney

@Maccath Nói một cách đơn giản: trong ví dụ thứ ba, bạn không biết hoặc phải biết rằng removeOrderthậm chí tồn tại, vì vậy bạn không thể phụ thuộc vào nó. Trong ví dụ thứ hai, bạn phải biết.
Esailija

Mặc dù tôi vẫn cảm thấy có nhiều cách tốt hơn để thực hiện những gì bạn đã mô tả ở đây, nhưng ít nhất tôi bị thuyết phục rằng phương pháp này có mục đích, đặc biệt là trong môi trường có nhiều nhà phát triển khác. +1
Jeffrey Sweeney

1
@Esailija - Cảm ơn bạn, tôi nghĩ rằng tôi hiểu rõ hơn một chút. Vì vậy, ... nếu tôi xóa hoàn toàn thuê bao, nó sẽ không bị lỗi hay bất cứ điều gì, nó sẽ không làm gì cả? Và bạn có nói điều này có thể hữu ích trong trường hợp bạn muốn thực hiện một hành động, nhưng không nhất thiết phải biết chức năng nào phù hợp nhất tại thời điểm xuất bản, nhưng người đăng ký có thể thay đổi tùy thuộc vào các yếu tố khác?
Maccath

1

Việc triển khai PubSub thường thấy ở những nơi có -

  1. Có một portlet giống như triển khai trong đó có nhiều portlet giao tiếp với sự trợ giúp của bus sự kiện. Điều này giúp tạo trong kiến ​​trúc aync.
  2. Trong một hệ thống bị hỏng bởi khớp nối chặt chẽ, pubsub là một cơ chế giúp giao tiếp giữa các mô-đun khác nhau.

Mã mẫu -

var pubSub = {};
(function(q) {

  var messages = [];

  q.subscribe = function(message, fn) {
    if (!messages[message]) {
      messages[message] = [];
    }
    messages[message].push(fn);
  }

  q.publish = function(message) {
    /* fetch all the subscribers and execute*/
    if (!messages[message]) {
      return false;
    } else {
      for (var message in messages) {
        for (var idx = 0; idx < messages[message].length; idx++) {
          if (messages[message][idx])
            messages[message][idx]();
        }
      }
    }
  }
})(pubSub);

pubSub.subscribe("event-A", function() {
  console.log('this is A');
});

pubSub.subscribe("event-A", function() {
  console.log('booyeah A');
});

pubSub.publish("event-A"); //executes the methods.

1

Bài báo "Nhiều khía cạnh của việc xuất bản / đăng ký" là một bài đọc tốt và một điều mà họ nhấn mạnh là phân tách thành ba "chiều". Đây là bản tóm tắt thô sơ của tôi, nhưng hãy tham khảo bài báo.

  1. Tách không gian.Các bên tương tác không cần biết nhau. Nhà xuất bản không biết ai đang nghe, bao nhiêu người đang nghe, hoặc họ đang làm gì với sự kiện này. Người đăng ký không biết ai đang sản xuất các sự kiện này, có bao nhiêu nhà sản xuất, v.v.
  2. Tách thời gian. Các bên tương tác không cần phải hoạt động cùng một lúc trong quá trình tương tác. Ví dụ: người đăng ký có thể bị ngắt kết nối trong khi nhà xuất bản đang xuất bản một số sự kiện, nhưng người đăng ký có thể phản ứng lại khi nó trực tuyến.
  3. Tách đồng bộ hóa. Các nhà xuất bản không bị chặn trong khi sản xuất sự kiện và người đăng ký có thể được thông báo không đồng bộ thông qua các cuộc gọi lại bất cứ khi nào một sự kiện mà họ đã đăng ký đến.

0

Câu trả lời đơn giản Câu hỏi ban đầu đang tìm kiếm một câu trả lời đơn giản. Đây là nỗ lực của tôi.

Javascript không cung cấp bất kỳ cơ chế nào để các đối tượng mã tạo sự kiện của riêng chúng. Vì vậy, bạn cần một loại cơ chế sự kiện. mô hình Xuất bản / đăng ký sẽ đáp ứng nhu cầu này và bạn có thể chọn một cơ chế phù hợp nhất với nhu cầu của mình.

Bây giờ chúng ta có thể thấy nhu cầu về mẫu pub / sub, sau đó bạn có muốn xử lý các sự kiện DOM khác với cách bạn xử lý các sự kiện pub / sub của mình không? Vì lợi ích của việc giảm độ phức tạp và các khái niệm khác như tách biệt các mối quan tâm (SoC), bạn có thể thấy lợi ích của mọi thứ là đồng nhất.

Vì vậy, nghịch lý là, càng nhiều mã sẽ tạo ra sự tách biệt tốt hơn các mối quan tâm, điều này có thể mở rộng đến các trang web rất phức tạp.

Tôi hy vọng ai đó thấy đây là một cuộc thảo luận đủ tốt mà không đi vào chi tiết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.