摘要:發布訂閱模式定義對象間的一種一對多的依賴關系當一個對象的狀態發生改變時所有依賴于它的對象都將得到通知簡單實現定義發布者緩存列表存放訂閱者的回調函數定義訂閱者發布消息測試訂閱者價格訂閱者價格發布消息上面的實現方式導致了每個訂閱者都會收到發布
發布-訂閱模式
定義對象間的一種 一對多 的依賴關系, 當一個對象的狀態發生改變時, 所有依賴于它的對象都將得到通知
簡單實現
</>復制代碼
// 定義發布者
var salesOffices = {};
// 緩存列表, 存放訂閱者的回調函數
salesOffices.clientList = [];
// 定義訂閱者
salesOffices.listen = function (fn) {
this.clientList.push(fn);
}
// 發布消息
salesOffices.trigger = function () {
for (var i = 0, fn; fn = this.clientList[i++];) {
fn.apply(this, arguments)
}
}
/*** 測試 ***/
// 訂閱者1
salesOffices.listen(function (price, squareMeter) {
console.log("價格=" + price);
console.log("squareMeter= " + squareMeter);
});
// 訂閱者2
salesOffices.listen(function (price, squareMeter) {
console.log("價格=" + price);
console.log("squareMeter= " + squareMeter);
});
// 發布消息
salesOffices.trigger(2000, 80);
salesOffices.trigger(3000, 100);
上面的實現方式, 導致了, 每個訂閱者都會收到發布者發布的消息
</>復制代碼
// 定義發布者
var salesOffices = {};
// 緩存列表, 存放訂閱者的回調函數
salesOffices.clientList = {};
// 定義訂閱者 (增加緩存, 增加標示 key )
salesOffices.listen = function (key, fn) {
if (!this.clientList[key]) {
this.clientList[key] = [];
}
this.clientList[key].push(fn);
}
// 發布消息
salesOffices.trigger = function () {
var key = Array.prototype.shift.call(arguments),
fns = this.clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments)
}
}
提煉發布-訂閱模式
</>復制代碼
// 核心事件
var event = {
clientList: {},
listen: function (key, fn) {
if (!this.clientList[key]) {
this.clientList[key] = [];
}
this.clientList[key].push(fn);
},
trigger: function () {
var key = Array.prototype.shift.call(arguments),
fns = this.clientList[key];
if (!fns || fns.length === 0) {
return false
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
}
}
// 取消訂閱消息
event.remove = function (key, fn) {
var fns = this.clientList[key];
if (!fns) {
return false;
}
if (!fn) {
// 沒有傳入fn 取消key對應的所有的訂閱
fns && (fns.length = 0);
} else {
// 傳入fn 刪除對應的fn
for (var l = fns.length - 1; l >= 0; l--) {
var _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1)
}
}
}
}
// 給任何對象動態增加發布-訂閱功能
var installEvent = function (obj) {
for (var key in event) {
if (event.hasOwnProperty(key)) {
obj[key] = event[key];
}
}
}
/*** 測試 ***/
var salesOffices = {};
installEvent(salesOffices);
// 訂閱者1
salesOffices.listen("squareMeter80", function (price) {
console.log("價格=" + price);
});
// 訂閱者2
salesOffices.listen("squareMeter100", function (price) {
console.log("價格=" + price);
});
// 發布消息
salesOffices.trigger("squareMeter80", 20000);
salesOffices.trigger("squareMeter100", 30000);
登錄案例
</>復制代碼
// 登錄成功, 發布成功消息
$.ajax("http://xxx.com/login", function (data) {
login.trigger("loginSuccess", data);
});
// 這種寫法也很好
var header = (function () {
// 訂閱消息
login.listen("loginSuccess", function (data) {
header.setAvatar(data);
})
return {
setAvatar: function (data) {
console.log("header 模塊拿到用戶信息")
}
}
})();
以上寫法會有三個問題
需要一個類似"中介者"的角色, 把發布者和訂閱者聯系起來(通過 全局的 Event 來解決)
以上必須先訂閱, 才能發布
全局命名的沖突
實現類似 Event 的發布-訂閱模式優點1: 時間上的解耦,
優點2: 對象之間的解耦
缺點1: 創建訂閱者本生要消耗內存和時間
缺點2: 弱化了對象之間的聯系之后, 對象之間的必要聯系也被埋沒
</>復制代碼
var Event = (function() {
var global = this,
Event,
_default = "default";
Event = function () {
var _listen,
_trigger,
_remove,
_slice = Array.prototype.slice,
_shift = Array.prototype.shift,
_unshift = Array.prototype.unshift,
namespaceCache = {},
_create,
find,
each = function(arr, fn) {
var ret;
for (var i = 0, l = arr.length; i < l; i++) {
var n = arr[i];
ret = fn.call(n, i, n);
}
return ret;
};
_listen = function (key, fn, cache) {
if (!cache[key]) {
cache[key] = [];
}
cache[key].push(fn);
};
_remove = function (key, cache, fn) {
if (cache[eky]) {
if (fn) {
for (var i = cache[key].length - 1; i >= 0; i--) {
if (cache[key][i] === fn) {
cache[key].splice(i, 1);
}
}
} else {
cache[key] = [];
}
}
}
_trigger = function () {
var cache = _shift.call(arguments),
key = _shift.call(arguments),
args = arguments,
_self = this,
ret,
stack = cache[key];
if (!stack || !stack.length) {
return;
}
return each(stack, function () {
return this.apply(_self, args);
})
};
_create = function (namespace) {
namespace = namespace || _default;
var cache = {},
offlineStack = [],
ret = {
listen: function (key, fn, last) {
_listen(key, fn, cache);
if (offlineStack === null) {
return;
}
if (last === "last") {
offlineStack.length && offlineStack.pop()();
} else {
each(offlineStack, function () {
this();
})
}
offlineStack = null;
},
one: function (key, fn, last) {
_remove(key, fn, cache);
this.listen(key, fn, last);
},
remove: function (key, fn) {
_remove(key, cache, fn);
},
trigger: function () {
var fn,
args,
_self = this;
_unshift.call(arguments, cache);
args = arguments;
fn = function () {
return _trigger.apply(_self, args);
}
if (offlineStack) {
return offlineStack.push(fn);
}
return fn();
}
};
return namespace
? (namespaceCache[namespace]
? namespaceCache[namespace]
: namespaceCache[namespace] = ret)
: ret
}
return {
create: _create,
one: function (key, fn, last) {
var event = this.create();
event.one(key, fn, last);
},
remove: function (key, fn) {
var event = this.create();
event.remove(key, fn);
},
listen: function (key, fn, last) {
var event = this.create();
event.listen(key, fn, last);
},
trigger: function () {
var event = this.create();
event.trigger.apply(this, arguments);
}
}
}()
return Event;
})();
觀察者(observer) 模式 和 發布/訂閱模式 之間的區別
本質上的區別及時在調度的地方不同
分清楚誰是發布者, 誰是觀察者, 誰是訂閱者
觀察者模式
</>復制代碼
// subject(發布) 中的目標發生變化. Observer(觀察) 能接受到變化
function ObserverList() {
this.observerList = [];
}
ObserverList.prototype.add = function (obj) {
return this.observerList.push(obj);
}
ObserverList.prototype.get = function (index) {
if (index > -1 && this.observerList.length) {
return this.observerList[index];
}
}
ObserverList.prototype.indexOf = function (obj, startIndex) {
var i = startIndex;
while(i < this.observerList.length) {
if (this.observerList[i] === obj) {
return i;
}
i++;
}
return -1;
}
ObserverList.prototype.removeAt = function (index) {
this.observerList.splice(index, 1);
}
// 發布者
function Subject() {
this.observers = new ObserverList();
}
Subject.prototype.addObserver = function (observer) {
this.observers.add(observer);
}
Subject.prototype.removeObserver = function (observer) {
this.observers.removeAt(this.observers.indexOf(observer, 0));
}
Subject.prototype.notify = function (context) {
var observerCount = this.observers.count();
for (var i = 0; i < observerCount; i++) {
this.observers.get(i).update(context);
}
}
// 觀察者
function Observer() {
this.update = function () {
// ...
}
}
發布(Publish)/訂閱(Subscribe)模式
</>復制代碼
var pubsub = {};
(function (myObject) {
var topics = {};
var subUid = -1;
// 發布
myObject.publish = function (topic, args) {
if (!topics[topic]) {
return false;
}
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args);
}
return this;
}
// 訂閱者
myObject.subscribe = function (topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
})
}
// 取消訂閱
myObject.unsubscribe = function (token) {
for (var m in topics) {
if (topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return this;
}
})(pubsub)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/104533.html
摘要:觀察者模式也稱發布訂閱模式它的作用就是當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知,自動刷新對象狀態舉個生活比較常見常見的例子比如你去面試之后,面試官看你表現不錯,最后會跟你要聯系方式,以便之后可以聯系你。 觀察者模式也稱發布-訂閱模式,它的作用就是當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知,自動刷新對象狀態 舉個生活比較常見常見的例子,比如你去面試之后,...
摘要:設計模式與開發實踐讀書筆記。發布訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。附設計模式之發布訂閱模式觀察者模式數據結構和算法系列棧隊列優先隊列循環隊列設計模式系列設計模式之策略模式 《JavaScript設計模式與開發實踐》讀書筆記。 發布-訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。當一個對象的狀態發生改變時,所有依賴它的對象都將得到通知。 例...
摘要:雙向數據綁定簡言之數據動頁面動,頁面動,數據動典型的應用就是在做表單時候,輸入框的內容改動后,跟該輸入框的的值改動。看官網上的這個的演示案例雙向數據綁定的好處要說出這個好處的時候,也只有在實際場景中才能對應的顯示出來。 前言:本系列學習筆記從以下幾個點展開 什么是雙向數據綁定 雙向數據綁定的好處 怎么實現雙向數據綁定 實現雙向數據數據綁定需要哪些知識點 數據劫持 發布訂閱模式 ...
摘要:設計模式與開發實踐讀書筆記。看此文章前,建議先看設計模式之發布訂閱模式觀察者模式在中,已經介紹了什么是發布訂閱模式,同時,也實現了發布訂閱模式。 《JavaScript設計模式與開發實踐》讀書筆記。 看此文章前,建議先看JavaScript設計模式之發布-訂閱模式(觀察者模式)-Part1 在Part1中,已經介紹了什么是發布-訂閱模式,同時,也實現了發布-訂閱模式。但是,就Part1...
閱讀 2621·2021-11-16 11:40
閱讀 3417·2021-11-08 13:26
閱讀 886·2021-10-28 09:32
閱讀 3542·2021-09-13 10:26
閱讀 815·2019-08-30 15:55
閱讀 788·2019-08-30 15:44
閱讀 1917·2019-08-30 15:44
閱讀 1762·2019-08-30 13:48