01 發布者訂閱者模式 js(js 怎么理解js事件觀察者模式)

时间:2024-05-18 14:31:34 编辑: 来源:

js 怎么理解js事件觀察者模式

觀察者模式主要應用于對象之間一對多的依賴關系,當一個對象發生改變時,多個對該對象有依賴的其他對象也會跟著做出相應改變,這就非常適合用觀察者模式來實現。使用觀察者模式可以根據需要增加或刪除對象,解決一對多對象間的耦合關系,使程序更易于擴展和維護。

基礎知識:

觀察者模式定義了對象間的一種一對多依賴關系,每當一個對象發生改變時,其相關依賴對象皆得到通知并被進行相應的改變。觀察者模式又叫做發布-訂閱模式。生活中有很多類似的關系,比如買粉絲買粉絲訂閱,多個讀者訂閱一個買粉絲買粉絲,一旦買粉絲有更新,多個讀者都會收到更新,而這種情況在應用程序中也非常常見,js綁定各種事件本質上就是觀察者模式的實現。

觀察者模式是一個非常有用的設計模式,它主要有兩個角色組成:

(1)目標對象:作為一對多關系中的一,可以用來管理觀察者的增加和刪除。

(2)觀察者對象:觀察目標對象,一旦目標發生改變則做出相應的反應。

vuejs源碼用了什么設計模式,具體點的

最簡單的訂閱者模式

// Observer

class Observer {

買粉絲nstructor (data) {

this.walk(data)

}

walk (data) {

// 遍歷

let keys = Object.keys(data)

for(let i = 0; i < keys.length; i++){

defineReactive(data, keys[i], data[keys[i]])

}

}

}

function defineReactive (data, key, val) {

observer(val)

// dep 為什么要在這里實例化, 就是為了實現, 對象每一層的 每一個key都有自己的一個訂閱實例, 比如 a.b 對應 dep1, a.c 對應dep2, 這里雖然都是let dep = new Dep()

// 但每次來到這個方法, dep都是獨立的, 會一直保留在內存. 這樣在每次調用set方法都能找到這個a.b對應的dep

// dep 這里會一直保存, 是因為閉包的關系, Object這個全局的函數, 引用了上層的作用域, 這個作用域包含了 dep, 除非Object = null, 或者退出瀏覽器, dep才會消失

//實例化之后, dep就有了被訂閱, 和發布消息的功能, dep不寫在這里也是可以的, 多定義一個全局函數, 每次obser的時候增加一個dep

let dep = new Dep()

Object.defineProperty(data, key, {

enumerable: true,

買粉絲nfigurable: true,

get: function () {

//每次new Watch('a.b'), 都會先執行get方法, 進而來到這里, 觸發 dep.depend(), 這個dep就是 a.b 對應的 訂閱,

dep.depend()

return val

},

set: function (newVal) {

if(val === newVal){

return

關于generator異步編程的理解以及如何動手寫

關于generator異步編程的理解以及如何動手寫一個買粉絲模塊

generator出現之前,想要實現對異步隊列中任務的流程控制,大概有這么一下幾種方式:

回調函數

事件監聽

發布/訂閱

promise對象

第一種方式想必大家是最常見的,其代碼組織方式如下:

請點擊輸入圖片描述

function fn(url, callback){ var 買粉絲Request;//創建XHR

買粉絲Request = window.XMLHttpRequest ? new XMLHttpRequest() :

window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;

 

買粉絲Request.onreadystatechange = function(){  if(買粉絲Request.readystate === 4 && 買粉絲Request.status === 200){ //狀態判斷   callback.call(買粉絲Request.responseXML);

 }

};

買粉絲Request.open("GET", url);

買粉絲Request.send();

}

fn("text.xml", function(){ //調用函數

買粉絲nsole.log(this); //此語句后輸出});

買粉絲nsole.log("this will run before the above callback.");//此語句先輸出

請點擊輸入圖片描述

對于一個普通的ajax異步請求來說,我么在請求開始的時候就要告訴他請求成功之后所要執行的動作,因此就可以類似以這種方式組織代碼,控制異步流程。這種調用方式最大的問題就是回調黑洞的問題,一層回調也還好,但涉及到二層、三層、n層的時候就讓代碼變得復雜很難維護。

第二種方式自己在前段時間使用backbone.js作為技術棧的項目的開發中深有體會,對于每一個ajax請求都對其分配一個自定義事件,在ajax成功返回數據的時候,就會觸發自定義的事件完成接下來的動作,控制異步流程,代碼如下:

請點擊輸入圖片描述

請點擊輸入圖片描述

第三種方式和第二種的方式性質上有些類似,如果從發布訂閱的角度來看,on方法相當于訂閱者/觀察者,trigger方法相當于發布者。原理上來說無非就是維護一個“消息中心”的數組,通過on方法訂閱的事件都會推入“消息中心”數組,最后發布的時候將會匹配“消息中心”數組的事件,進而執行相應的流程。

我們通過jquery的sub/pub插件完成一個很簡單的演示。

首先,f2向"信號中心"jQuery訂閱"done"信號。

請點擊輸入圖片描述

jQuery.subscribe("done", f2);

function f1(){

setTimeout(function () {

// f1的任務代碼

jQuery.publish("done");

}, 1000);

}

f1();

請點擊輸入圖片描述

jQuery.publish("done")的意思是,f1執行完成后,向"信號中心"jQuery發布"done"信號,從而引發f2的執行。

第四種方式promise范式,先看一段代碼:

請點擊輸入圖片描述

我們只要并且僅需要new一個promise對象,就會發現promise對象的參數函數已經執行了,隔兩秒之后輸出"執行完成"。

接下來再看一段其實際應用的場景代碼:

請點擊輸入圖片描述

從本質上來看,Promise是一個構造函數,其本身有all、reject、resolve等方法,同時其原型上有then、catch等方法。通過其用Promise new出來的對象自然就有then、catch方法。然后可以通過then方法中的回調函數,獲取到上一段異步操作中返回(通過resolve)的數據。從而實現對異步操作的流程控制。

但我的每個函數都得被promise對象包裝一下,同時一大堆的then...真是一個聽蛋疼的事兒...

綜上所述對于異步流程的控制,都有其自身的缺陷,我們最理想的方式便是像操作同步流程那樣實現對異步流程的控制,試想一下這樣的異步操作流程(加了層層包裝,proxy便是發送一個異步請求,接下來的代碼便是獲取到異步操作返回的數據,細節可暫時忽略):

請點擊輸入圖片描述

這感覺就是真他媽的舒服,怎么實現這么一個讓人很爽的東西呢,于是我們的主角---偉大的Generator函數登場了。

先理解這么自己悟的一句話:

"javascript是單線程的,順序執行一段代碼,執行到了異步操作,按正常的邏輯走的話就是主隊列中的代碼繼續執行,這時異步隊列中的代碼還未執行,我們繼續執行的代碼也就會發生報錯。那么解決問題的關鍵就是,我們能夠手動控制代碼的向下執行,配合一個東西監聽到異步操作的已經正常返回了之后,去手動的操作代碼的執行流程,這樣的話就實現了已同步的方式控制異步代碼的執行" 

那么問題變成了解決兩個問題。

1、我們是如何實現對于異步操作是否成功返回的監聽。

2、如何手動操作代碼的向下執行。

對于第一個問題,我們采用的方案是使用promise對象的方式,Promise 的編程思想便是,用于“當xx數據準備完畢,then執行xx動作”這樣的場景,用在這里再適合不過。

對于第二個問題,我們便是采用偉大的generator生成器函數,其中的yield特性,可以使我們手動的控制代碼的向下執行。

接下來我們實際的解決一個問題:實現對于讀取文件異步操作的控制,當讀取完文件之后打印讀取的內容。

我們依賴于node環境,首先通過promise對其進行封裝,實現數據成功的監聽。我們手下代碼如下:

請點擊輸入圖片描述

var fs = require(

搜索关键词: