跨标签页通信的8种方式(下)

本文介绍了在Web开发中如何在不同标签页间进行数据共享,重点关注了SharedWorker、IndexedDB、Cookie和Websocket这四种跨标签页通信方式,以及它们各自的适用场景和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跨标签页通信是指在浏览器中的不同标签页之间进行数据传递和通信的过程。在传统的Web开发中,每个标签页都是相互独立的,无法直接共享数据。然而,有时候我们需要在不同的标签页之间进行数据共享或者实现一些协同操作,这就需要使用跨标签页通信来实现。

常见的跨标签页方案如下:

  • BroadCast Channel

  • Service Worker

  • LocalStorage window.onstorage 监听

  • window.open、window.postMessage

  • Shared Worker 定时器轮询( setInterval

  • IndexedDB 定时器轮询( setInterval

  • cookie 定时器轮询( setInterval

  • Websocket

前面4种方式可见: 跨标签页通信的8种方式(上)

本文介绍后面4种

Shared Worker

Shared Worker 是一种在多个浏览器标签页之间共享的 JavaScript 线程。它可以用于实现跨标签页的通信。

SharedWorker 接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。它们实现一个不同于普通 worker 的接口,具有不同的全局作用域,

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

兼容性

  1. 下面是一个使用 Shared Worker 进行通信的示例:

在主页面中:

// 创建一个 Shared Worker
const worker = new SharedWorker('worker.js');

// 监听来自 Shared Worker 的消息
worker.port.onmessage = function(event) {
  console.log('Received message from worker:', event.data);
};

// 向 Shared Worker 发送消息
worker.port.postMessage('Hello from main page!');

在 worker.js 文件中:

// 监听来自主页面的消息
self.onconnect = function(event) {
  const port = event.ports[0];
  
  // 监听来自主页面的消息
  port.onmessage = function(event) {
    console.log('Received message from main page:', event.data);
    
    // 向主页面发送消息
    port.postMessage('Hello from shared worker!');
  };
};

IndexedDB

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。

IndexedDB 是一个事务型数据库系统,类似于基于 SQL 的 RDBMS。然而,不像 RDBMS 使用固定列表,IndexedDB 是一个基于 JavaScript 的面向对象数据库。IndexedDB 允许你存储和检索用索引的对象;可以存储结构化克隆算法支持的任何对象。你只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务

使用 IndexedDB 执行的操作是异步执行的,以免阻塞应用程序。

IndexedDB 是浏览器提供的一种本地数据库,可以用于在多个标签页之间共享数据。可以使用 setInterval 定时轮询 IndexedDB 来实现跨标签页通信。下面是一个示例:

在发送消息的标签页中:

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

request.onupgradeneeded = function(event) {
  const db = event.target.result;
  
  // 创建一个对象存储空间用于存储消息
  db.createObjectStore('messages', { keyPath: 'id', autoIncrement: true });
};

request.onsuccess = function(event) {
  const db = event.target.result;
  
  // 向数据库中添加一条新消息
  const transaction = db.transaction(['messages'], 'readwrite');
  const objectStore = transaction.objectStore('messages');
  
  const message = { content: 'Hello from sender!' };
  
  objectStore.add(message);
  
  transaction.oncomplete = function() {
    console.log('Message sent successfully!');
    
    // 关闭数据库连接
    db.close();
  };
};

request.onerror = function(event) {
  console.error('Error opening database:', event.target.error);
};

在接收消息的标签页中:

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

request.onsuccess = function(event) {
  const db = event.target.result;
  
  // 创建一个定时器,每隔一段时间轮询数据库中的消息
  setInterval(function() {
    // 创建一个事务
    const transaction = db.transaction(['messages'], 'readwrite');
    const objectStore = transaction.objectStore('messages');
    
    // 获取存储在对象存储中的所有消息
    const request = objectStore.getAll();
    
    request.onsuccess = function(event) {
      const messages = event.target.result;
      
      // 处理消息
      messages.forEach(function(message) {
        console.log('Received message:', message.content);
        
        // 在处理完消息后,删除该消息
        objectStore.delete(message.id);
      });
      
      // 关闭事务
      transaction.oncomplete = function() {
        console.log('Messages processed successfully!');
      };
    };
    
    request.onerror = function(event) {
      console.error('Error retrieving messages:', event.target.error);
      
      // 关闭事务
      transaction.abort();
    };
  }, 1000);
};

request.onerror = function(event) {
  console.error('Error opening database:', event.target.error);
};

在上述示例中,我们创建了一个名为 "messageDatabase" 的 IndexedDB 数据库,并在其中创建了一个名为 "messages" 的对象存储空间用于存储消息。在发送消息的标签页中,我们向数据库中添加一条新消息。而在接收消息的标签页中,我们创建了一个定时器,每隔一段时间轮询数据库中的消息,并处理这些消息。处理完消息后,我们将其从数据库中删除。

请注意,在实际应用中,您可能需要更复杂的逻辑来处理跨标签页通信,并确保数据同步和一致性。此示例仅提供了一个基本的框架来演示如何使用 IndexedDB 实现跨标签页通信。

cookie

Cookie 是一种在浏览器和服务器之间传递的小型文本文件,可以用于在多个标签页之间共享数据。可以使用 setInterval 定时轮询 Cookie 来实现跨标签页通信。下面是一个示例:

在发送消息的标签页中:

// 设置一个 Cookie,将消息存储在 Cookie 中
document.cookie = 'message=Hello from sender!';

在接收消息的标签页中:

// 创建一个定时器,每隔一段时间轮询 Cookie 中的数据
setInterval(function () {
  // 获取存储在 Cookie 中的消息
  const cookies = document.cookie.split(';')
  let message = ''

  for (let i = 0; i < cookies.length; i++) {
    const cookie = cookies[i].trim()

    if (cookie.startsWith('message=')) {
      message = cookie.substring('message='.length)
      break
    }
  }

  // 处理消息
  if (message) {
    console.log('Received message:', decodeURIComponent(message))

    // 清除 Cookie
    document.cookie = 'message=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
  }
}, 1000)

在上述示例中,我们在发送消息的标签页中设置了一个名为 "message" 的 Cookie,并将消息存储在其中。而在接收消息的标签页中,我们创建了一个定时器,每隔一段时间轮询 Cookie 中的数据。通过解析和处理 Cookie,我们可以获取到存储的消息,并进行相应的处理。处理完消息后,我们清除了该 Cookie。 请注意,在使用 Cookie 进行跨标签页通信时,需要注意以下几点:

  • 跨域名通信:Cookie 默认只能在同一域名下共享。如果需要在不同域名下进行跨标签页通信,需要设置合适的域名和路径。
  • Cookie 大小限制:Cookie 的大小有限制,通常为几 KB。如果消息较大,可能需要拆分成多个 Cookie 进行存储。
  • 安全性考虑:Cookie 中的数据可以被用户和其他脚本访问和修改。因此,不适合存储敏感信息。 以上示例提供了一个基本的框架来演示如何使用 Cookie 实现跨标签页通信。在实际应用中,您可能需要更复杂的逻辑来处理跨标签页通信,并确保数据同步和一致性。

websocket

Websocket 是一种在浏览器和服务器之间进行全双工通信的协议,可以用于实现实时的跨标签页通信。下面是一个使用 Websocket 进行通信的示例:

在发送消息的标签页中:

// 创建一个 WebSocket 连接
const socket = new WebSocket('ws://example.com');
// 监听连接成功的事件
socket.onopen = function() {
 // 发送消息到服务器
  socket.send('Hello from sender!');
};

在接收消息的标签页中:

// 创建一个 WebSocket 连接
const socket = new WebSocket('ws://example.com');
// 监听来自服务器的消息
socket.onmessage = function(event) {
  console.log('Received message:', event.data);
};

在服务器端:

// 创建一个 WebSocket 服务器
const WebSocketServer = require('ws').Server
const wss = new WebSocketServer({ port: 8080 })
// 监听来自客户端的连接
wss.on('connection', function (socket) {
  // 监听来自客户端的消息
  socket.on('message', function (message) {
    console.log('Received message:', message)

    // 向所有客户端发送消息
    wss.clients.forEach(function (client) {
      client.send(message)
    })
  })
})

在上述示例中,我们在发送消息的标签页中创建了一个 WebSocket 连接,并在连接成功后发送一条消息到服务器。而在接收消息的标签页中,我们也创建了一个 WebSocket 连接,并监听来自服务器的消息。当服务器收到来自任何客户端的消息时,它会将该消息广播给所有连接的客户端。

总结

这些通信方式各有优劣,选择适合的方式取决于具体的需求和场景。Shared Worker 和 Websocket 提供了实时性和双向通信的能力,适用于需要实时更新和交互的应用。IndexedDB 和 Cookie 则适用于需要存储和同步数据的场景,但相对于实时性较差。根据具体需求,可以选择合适的通信方式来实现跨标签页的通信。

### 浏览器跨标签页通信的方法和技术 在现代Web应用中,实现浏览器不同标签页间的高效通信至关重要。以下是几种常见的方法及其技术细节: #### 1. 使用LocalStorage事件监听机制 当在一个窗口或标签页中修改 `localStorage` 数据时,其他同源的窗口会触发相应的存储事件。这使得开发者可以在多个标签页之间传递消息。 ```javascript // 发送端:设置 localStorage 来发送数据 window.localStorage.setItem('message', JSON.stringify({ type: 'greeting', content: 'Hello from Tab A' })); // 接收端:监听 storage 事件来接收数据 window.addEventListener('storage', function(event) { if (event.key === 'message') { console.log(JSON.parse(event.newValue)); } }); ``` 这种方法简单易用,但存在一定的延迟,并且每次更改都会刷新整个本地存储[^1]。 #### 2. 广播通道 API (Broadcast Channel API) 广播通道允许同一源下的所有上下文(如不同的标签页、iframe 或 service worker)通过命名频道相互通信。它提供了更高效的实时双向通讯方式。 ```javascript const bc = new BroadcastChannel('example_channel'); bc.postMessage({ action: 'ping', data: 'some info' }); bc.onmessage = ({data}) => { console.log(`Received message ${JSON.stringify(data)}`); }; ``` 此接口具有更好的性能表现和更低的消息传输延迟,适合频繁的数据交换场景[^2]。 #### 3. Shared Worker 共享工作线程可以被同一个域内的多个脚本文件共同访问并执行异步任务。利用 shared workers 可以创建一个中间层来进行多标签页间的信息同步。 ```javascript if (!navigator.serviceWorker.controller && window.Worker) { const mySharedWorker = new SharedWorker('/path/to/shared-worker.js'); mySharedWorker.port.start(); } ``` 这种方式适用于需要长时间运行后台进程的应用程序,不过需要注意的是并非所有的浏览器都支持该特性[^3]。 #### 4. Cookies 和 SessionStorage 结合轮询 虽然这不是最理想的解决方案,但在某些情况下也可以考虑使用 cookies 加上定时查询 sessionStorage 的变化情况来间接达到目的。然而由于其效率低下以及可能带来的安全风险,在实际项目中应谨慎采用这种做法。 综上所述,对于大多数应用场景而言,推荐优先选用 **Broadcast Channel API** 进行跨标签页通信;而对于一些特殊需求,则可以根据具体情况评估是否适用 LocalStorage 或者 Shared Workers 方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想是坚持

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值