简说浏览器跨标签页通信方式

  • • 浏览器跨标签页通信

      • • Broadcast Channel API:

      • • LocalStorage/SessionStorage:

      • • SharedWorker:

      • • Cookies + setInterval:

      • • WebSocket:

      • • postMessage (适用于同源或跨源场景,如 iframe、窗口间通信):

      • • IndexedDB

      • • 服务器端存储 

浏览器跨标签页通信

浏览器跨标签页通信是指在同一个浏览器进程中,不同标签页之间进行数据交换和消息传递。

由于浏览器默认将每个标签页视为独立的执行环境(即每个标签页有自己的全局作用域和事件循环),它们之间不能直接访问彼此的内存空间或变量。

然而,为了满足一些应用场景的需求,如实时状态同步、协同编辑、通知传递等,开发者可以利用浏览器提供的API和机制实现跨标签页通信。

以下是实现这一目标的常见方式,包括技术原理和简要示例:

Broadcast Channel API:

  • • 原理:Broadcast Channel API 提供了一个内置通道,允许来自同一源(相同协议、主机名和端口)的多个浏览上下文(如标签页、窗口、服务工作线程)进行双向通信。

  • • 示例

    // 发送消息的标签页
    const channel = new BroadcastChannel('my-channel');
    channel.postMessage({ message'Hello from tab A' });

    // 接收消息的标签页
    const channel = new BroadcastChannel('my-channel');
    channel.addEventListener('message', (event) => {
    console.log(`Received message: ${event.data.message}`);
    });

LocalStorage/SessionStorage:

  • • 原理:这两个浏览器存储API提供了在同一浏览器实例中跨标签页共享数据的能力。当数据发生变化时,会触发 storage 事件,其他标签页可以通过监听此事件来获取更新。

  • • 示例

    // 写入数据的标签页
    localStorage.setItem('sharedData'JSON.stringify({ key'value' }));

    // 监听数据变化的标签页
    window.addEventListener('storage', (event) => {
    if (event.key === 'sharedData') {
        const data = JSON.parse(event.newValue);
        console.log(`Updated data: ${data.key}`);
    }
    });

SharedWorker:

  • • 原理:SharedWorker 是一种可以被多个浏览器上下文共享的 Web Worker 实例,它创建一个独立的线程,使得多个标签页可以通过与该 Worker 通信来互相交互。

  • • 示例

    // SharedWorker 脚本(shared-worker.js)
    self.onconnect = function(e) {
    const port = e.ports[0];
    port.onmessage = function(e) {
        console.log(`Received from tab: ${e.data}`);
        // 广播给所有连接的标签页
        port.postMessage(`Message from SharedWorker: ${e.data}`);
    };
    };

    // 在各个标签页中连接到 SharedWorker
    const worker = new SharedWorker('shared-worker.js');
    worker.port.addEventListener('message', (event) => {
    console.log(`Received from SharedWorker: ${event.data}`);
    });
    worker.port.start();
    worker.port.postMessage('Hello from tab');

Cookies + setInterval:

  • • 原理:利用 cookies 存储跨标签页共享的信息,并通过定时器定期检查 cookie 值的变化来实现通信。

  • • 示例

    // 设置 cookie 的标签页
    document.cookie = 'crossTabMessage=Hello%20from%20tab%20A';

    // 检查 cookie 更新的标签页
    function checkCookieChanges() {
    const currentCookie = document.cookie.replace(/(?:(?:^|.*;s*)crossTabMessages*=s*([^;]*).*$)|^.*$/"$1");
    if (currentCookie !== lastCookieValue) {
        console.log(`Received cookie message: ${currentCookie}`);
        lastCookieValue = currentCookie;
    }
    }
    let lastCookieValue = '';
    setInterval(checkCookieChanges, 1000); // 每秒检查一次

WebSocket:

  • • 原理:WebSocket 是一种全双工的网络协议,允许服务器与客户端建立持久的连接并双向实时通信。虽然主要用于浏览器与服务器间的通信,但可以通过服务器作为中介实现跨标签页通信。

  • • 示例(简化版,未包含服务器部分):

    // 所有标签页连接到同一 WebSocket 服务器
    const socket = new WebSocket('ws://example.com/socket');

    socket.addEventListener('message', (event) => {
    console.log(`Received message from server: ${event.data}`);
    });

    // 当某个标签页需要发送消息时
    socket.send('Hello from tab');

postMessage (适用于同源或跨源场景,如 iframe、窗口间通信):

  • • 原理window.postMessage() 方法允许来自不同源的脚本采用安全的方式进行通信。尽管您提到的问题是关于跨标签页通信,但这里也提及 postMessage 以涵盖可能的上下文,如嵌入的 iframe 之间的通信。

  • • 示例(假设两个同源标签页间通信):

    // 发送消息的标签页
    otherWindow = window.open('other-page.html');
    otherWindow.postMessage({ message'Hello from tab A' }, '*');

    // 接收消息的标签页
    window.addEventListener('message', (event) => {
        if (event.origin === 'https://example.com') { // 验证来源
            console.log(`Received message: ${event.data.message}`);
        }
    });

IndexedDB

  • • 原理IndexedDB 是浏览器提供的一个客户端数据库,可以在不同的标签页之间存储和读取数据。

  • • 一个标签页可以将数据写入 IndexedDB,其他标签页可以监听 IndexedDB 的变化事件或定时从 IndexedDB 中读取数据来实现数据的共享和状态的同步。

// 打开或创建IndexedDB数据库
const request = indexedDB.open('myDatabase'1);

// 成功打开数据库
request.onsuccess = function(event) {
  const db = event.target.result;

  // 创建一个对象存储空间(类似表)
  const objectStore = db.createObjectStore('messages', { keyPath'id'autoIncrementtrue });

  // 添加一条消息到对象存储空间
  const message = { text'Hello, World!' };
  const addRequest = objectStore.add(message);

  addRequest.onsuccess = function(event) {
    console.log('消息已添加到IndexedDB');
  };

  addRequest.onerror = function(event) {
    console.error('添加消息到IndexedDB时发生错误');
  };

  // 从对象存储空间获取所有消息
  const getAllRequest = objectStore.getAll();

  getAllRequest.onsuccess = function(event) {
    const messages = event.target.result;
    console.log('所有消息:', messages);
  };

  getAllRequest.onerror = function(event) {
    console.error('获取消息时发生错误');
  };
};

// 打开或创建数据库时发生错误
request.onerror = function(event) {
  console.error('打开/创建数据库时发生错误');
};

// 数据库版本变更
request.onupgradeneeded = function(event) {
  const db = event.target.result;

  // 创建一个对象存储空间
  const objectStore = db.createObjectStore('messages', { keyPath'id'autoIncrementtrue });

  console.log('数据库版本已更新');
};

服务器端存储

将需要共享的数据存储在服务器端,标签页之间通过与服务器进行通信来获取和更新数据。可以使用 AJAX、WebSocket 或其他网络通信技术来实现与服务器的数据交互。

综上所述,浏览器内跨标签页通信可以通过 Broadcast Channel API、LocalStorage/SessionStorage、SharedWorker、Cookies + setInterval、WebSocket、以及在特定场景下的 postMessage 等方式实现。

选择何种方式取决于实际需求,如数据同步的实时性、是否需要服务器中介、是否涉及跨源通信等。

更多详细内容,请微信搜索“前端爱好者, 戳我 查看 。

BroadcastChannel

MDN 地址:https://developer.mozilla.org/zh-CN/docs/Web/API/BroadcastChannel

BroadcastChannel接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。

它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。

通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。

SharedWorker

MDN地址:https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker

SharedWorker 接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。

它们实现一个不同于普通 worker 的接口,具有不同的全局作用域,SharedWorkerGlobalScope 。

备注: 如果要使 SharedWorker 连接到多个不同的页面,这些页面必须是同源的(相同的协议、host 以及端口)

window.postMessage

MDN地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

window.postMessage() 方法可以安全地实现跨源通信。

通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。

window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件 (en-US)。传递给 window.postMessage() 的参数(比如 message)将通过消息事件对象暴露给接收消息的窗口。


原文始发于微信公众号(前端爱好者):简说浏览器跨标签页通信方式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/272572.html

(0)
木子先生的头像木子先生

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!