SharedWorker 通讯的原理

SharedWorker 是一种允许多个浏览器上下文(如标签页、iframe)共享一个 Worker 实例的技术,能够实现跨多个上下文的通讯和数据共享。通过 SharedWorker,我们可以在同一来源(同一协议、主机名和端口号)下的不同浏览器上下文之间进行高效的通讯。

SharedWorker 的基本概念

  1. SharedWorker 实例:多个上下文共享一个 Worker 实例,所有上下文可以通过这个 Worker 实例进行通讯。
  2. 连接和通讯:每个上下文通过 port 对象与 SharedWorker 通讯,portMessagePort 的实例。
  3. 消息传递:通过 postMessage 方法发送消息,通过 onmessage 事件处理器接收消息。

基本用法

1. 创建和连接 SharedWorker

在 JavaScript 文件中定义 SharedWorker 脚本。

// sharedWorker.js
self.onconnect = function(event) {
    const port = event.ports[0];
    port.onmessage = function(event) {
        // 处理来自页面的消息
        console.log('Received from page:', event.data);
        
        // 可以将消息发送给其他连接的端口
        port.postMessage('Reply from SharedWorker');
    };
};

在 HTML 页面中创建并连接 SharedWorker。

// 页面 A 和页面 B 中的代码
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;

// 发送消息
port.postMessage('Hello from Page');

// 接收消息
port.onmessage = (event) => {
    console.log('Received from SharedWorker:', event.data);
};

工作流程图

以下是 SharedWorker 实现不同标签页之间通讯的工作流程图:

┌──────────────────────┐                ┌──────────────────────┐
│      Page A          │                │      Page B          │
│                      │                │                      │
│ SharedWorker         │                │ SharedWorker         │
│   'sharedWorker.js'  │                │   'sharedWorker.js'  │
│          │           │                │          │           │
│          ▼           │                │          ▼           │
│  port.postMessage    │                │  port.postMessage    │
│  ('Hello from A')    │                │  ('Hello from B')    │
│          │           │                │          │           │
│          ▼           │                │          ▼           │
│  port.onmessage      │                │  port.onmessage      │
│  event.data ===      │                │  event.data ===      │
│  'Reply from Worker' │                │  'Reply from Worker' │
└──────────────────────┘                └──────────────────────┘

示例代码

SharedWorker 脚本

sharedWorker.js

let connections = [];

self.onconnect = function(event) {
    const port = event.ports[0];
    connections.push(port);

    port.onmessage = function(event) {
        console.log('Received from page:', event.data);
        
        // 广播消息给所有连接的端口
        connections.forEach(conn => {
            if (conn !== port) {
                conn.postMessage(event.data);
            }
        });
    };
    
    port.start();
};
标签页 A 的代码
<!DOCTYPE html>
<html>
<head>
    <title>Page A</title>
</head>
<body>
    <button onclick="sendMessage()">Send Message</button>

    <script>
        const sharedWorker = new SharedWorker('sharedWorker.js');
        const port = sharedWorker.port;

        port.start();

        function sendMessage() {
            port.postMessage('Hello from Page A');
        }

        port.onmessage = (event) => {
            console.log('Received from SharedWorker:', event.data);
        };
    </script>
</body>
</html>
标签页 B 的代码
<!DOCTYPE html>
<html>
<head>
    <title>Page B</title>
</head>
<body>
    <script>
        const sharedWorker = new SharedWorker('sharedWorker.js');
        const port = sharedWorker.port;

        port.start();

        port.onmessage = (event) => {
            console.log('Received from SharedWorker:', event.data);
        };
    </script>
</body>
</html>

SharedWorker 的特点和优缺点

特点
  1. 共享实例:多个上下文共享一个 Worker 实例,节省资源。
  2. 双向通讯:通过 MessagePort 实现双向通讯。
  3. 同源策略:确保安全性,只有同源的上下文才能相互通讯。
优点
  1. 高效资源利用:共享一个 Worker 实例,减少内存和 CPU 占用。
  2. 灵活的消息处理:可以在 Worker 中集中处理和分发消息,适用于复杂的通讯需求。
  3. 持久连接:连接建立后可以长时间保持,不需要频繁建立和销毁连接。
缺点
  1. 实现复杂:相比 BroadcastChannel,实现起来稍微复杂一些。
  2. 同源限制:只能在同源上下文之间通讯,不同来源无法相互通讯。
  3. 浏览器支持:部分旧版浏览器可能不支持 SharedWorker

实际应用场景

1. 用户登录状态同步

当用户在一个标签页中登录或注销,其他打开同一应用的标签页需要同步登录状态。

// SharedWorker 脚本
self.onconnect = function(event) {
    const port = event.ports[0];
    port.onmessage = function(event) {
        if (event.data === 'User logged in') {
            port.postMessage('User logged in');
        } else if (event.data === 'User logged out') {
            port.postMessage('User logged out');
        }
    };
    port.start();
};

// 标签页中使用
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;
port.start();

port.postMessage('User logged in');

port.onmessage = (event) => {
    if (event.data === 'User logged in') {
        // 同步用户登录状态
    } else if (event.data === 'User logged out') {
        // 同步用户注销状态
    }
};
2. 实时数据更新

在一个标签页中更新数据,其他标签页需要实时显示更新结果,例如股票行情、实时聊天消息等。

// SharedWorker 脚本
let connections = [];

self.onconnect = function(event) {
    const port = event.ports[0];
    connections.push(port);

    port.onmessage = function(event) {
        connections.forEach(conn => {
            if (conn !== port) {
                conn.postMessage(event.data);
            }
        });
    };

    port.start();
};

// 标签页中使用
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;
port.start();

port.postMessage('New data available');

port.onmessage = (event) => {
    console.log('Received data update:', event.data);
    // 更新界面显示
};
3. 多标签页协同工作

用户在多个标签页中打开同一个应用,需要各标签页协同工作。例如,在一个标签页中填写表单,另一个标签页显示表单预览。

// SharedWorker 脚本
let connections = [];

self.onconnect = function(event) {
    const port = event.ports[0];
    connections.push(port);

    port.onmessage = function(event) {
        connections.forEach(conn => {
            if (conn !== port) {
                conn.postMessage(event.data);
            }
        });
    };

    port.start();
};

// 标签页中使用
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;
port.start();

document.getElementById('formInput').addEventListener('input', (event) => {
    port.postMessage({ type: 'form_update', value: event.target.value });
});

port.onmessage = (event) => {
    if (event.data.type === 'form_update') {
        document.getElementById('formPreview').innerText = event.data.value;
    }
};

总结

SharedWorker 提供了一种强大的方法,用于在同源的不同浏览器上下文之间进行高效的通讯和数据共享。它特别适合需要共享资源和长时间保持连接的应用场景,如用户登录状态同步、实时数据更新和多标签页协同工作。通过掌握 SharedWorker 的使用方法,开发者可以大大提升 web 应用的用户体验和功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值