动态

详情 返回 返回

關於不同窗口,訂閲不生效的問題 - 动态 详情

問題

兩個窗口,顯示組件,A窗口顯示A組件,B窗口顯示B組件,兩個組件共同訂閲一個Service中的Subject,當在A組件中進行修改後,Service中的Subject發送通知,“值變更了”,B組件訂閲不到。

image.png

現在打開兩個窗口,每個窗口顯示一個組件,每個組件都訂閲 Service 中的 subjectTest, 在AComponent組件中,每隔一秒發送一條數據:

AComponent 組件中

    let i = 0;
    interval(1000).subscribe(() => {
      this.systemService.abc(++i);
    })

    this.systemService.subjectTest.subscribe(v => {
      console.log("AComponent收到了通知", v);
    });

Service:

subjectTest = new Subject<any>();

abc(s :any) {
 console.log('發送通知', s)
 this.subjectTest.next(s)
}

BComponent組件中也訂閲:

this.systemService.subjectTest.subscribe(v => {
      console.log('B Component 組件收到了通知',v);
    })

效果如下:
藍色窗口:AComponet

紅色窗口:BComponent

可以看AComponent一值在調用abc()方法,發送通知,AComponent組件收到了通知,BComponent組件並沒有。

image.png

問題分析

我們當前 編寫的都是 ts 代碼,ts不能在 瀏覽器中直接運行,需要編譯 成js文件,在瀏覽器中運行。

JS 內存模型

js的內存主要分為兩個部分:棧 和 堆

棧 (Stack)

後進先出原則

🌰: 當調用一個函數時,函數的局部變量、參數和返回地址會被壓入棧,函數調用結束後,數據會從棧中彈出。

堆 (Heap)

存儲複雜和動態分配的對象

🌰: 聲明一個全局變量,引入service、定義Subject,都存儲在堆中。

瀏覽器新建一個窗口

每個窗口都是獨立的 棧 和 堆 :
在:藍色窗口中定義一個a變量,進行打印,沒問題,在紅色窗口中輸出輸出 a 是一個 為定義的變量。
image.png

所以當在AComponet 中訂閲了subjectTest,調用了 abc(), 發送了推送,AComponet組件也接受到了,而BComponent 雖然訂閲了subject 卻收不到通知,是因為兩個 sujectTest 是兩個獨立的可訂閲變量。

解決

利用瀏覽器的 localStorage 事件

在AComponet 組件中加入:localStorage事件

因為需要在AComponet 組件中發送 通知,那麼當AComponet 收到通知後,發送localStorage 事件

image.png

在BComponent 組件中監聽storage 事件,在判斷是否是響應 鍵。

window.addEventListener('storage', (event) => {
      if (event.key === 'push') {
        console.log('ndexComponent 組件收到了通知', event.newValue);
      }
    });

只有 同源 頁面(相同的協議、域名和端口)才會響應 storage 事件。
在同一個標籤頁中對 localStorage 的修改不會觸發 storage 事件。

藍色窗口:AComponet

紅色窗口:BComponent

image.png

使用 Broadcast Channel

一個所有同源頁面都可以共享的(廣播)頻道,因此其中某一個頁面發送的消息可以被其他頁面監聽到。

在A組件中繼續每隔 3s 發佈一次

    let i = 0;
    interval(1000 * 3).subscribe(() => {
      this.systemService.abc(++i);
    });

service 中定義 BroadcastChannel,創建通道名稱為“push”,只有頻道相同才互通。

channel = new BroadcastChannel('push');

abc(s :any) {
    console.log('發送通知', s)
    this.channel.postMessage(s);
  }

B組件:

this.systemService.channel.onmessage = (event) => {
      console.log('BComponent 組件收到了通知',event.data);
    }

效果:

藍色窗口:AComponet

紅色窗口:BComponent

image.png

總結:

兩者都可以跨窗口同步信息, 兩者最主要的區別的在於,數據持久化。
localStorage的數據保存在瀏覽器中,刷新頁面,數據依舊存在。
BroadcastChannel的數據在會話中。刷新頁面,之前的數據就沒有了,得重新開始。

相對使用環境:使用BroadcastChannel更適合我們,刷新後,我們重新請求後台,已是最新數據,而且更改輪詢時間等,都是看着不對眼,才會設置。

user avatar tianmiaogongzuoshi_5ca47d59bef41 头像 freeman_tian 头像 longlong688 头像 huajianketang 头像 zero_dev 头像 youyoufei 头像 milton 头像 laggage 头像 beckyyyy 头像 yuhuashi_584a46acea21f 头像 gomi 头像 abcdxj555 头像
点赞 40 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.