阅山

  • WIN
    • CSharp
    • JAVA
    • OAM
    • DirectX
    • Emgucv
  • UNIX
    • FFmpeg
    • QT
    • Python
    • Opencv
    • Openwrt
    • Twisted
    • Design Patterns
    • Mysql
    • Mycat
    • MariaDB
    • Make
    • OAM
    • Supervisor
    • Nginx
    • KVM
    • Docker
    • OpenStack
  • WEB
    • ASP
    • Node.js
    • PHP
    • Directadmin
    • Openssl
    • Regex
  • APP
    • Android
  • AI
    • Algorithm
    • Deep Learning
    • Machine Learning
  • IOT
    • Device
    • MSP430
  • DIY
    • Algorithm
    • Design Patterns
    • MATH
    • X98 AIR 3G
    • Tucao
    • fun
  • LIFE
    • 美食
    • 关于我
  • LINKS
  • ME
Claves
阅山笑看风云起,意气扬帆向日辉
  1. 首页
  2. Programming
  3. javascript
  4. 正文

多iframe通信方案

2026-03-27

直接说结论:
你这个场景(多 iframe + 工业系统 + 并发调用)——必须用 postMessage + MessageChannel + Promise RPC,这是浏览器内通信的“准工业级方案”。

我给你一个可落地的完整设计,重点解决:

  • 多 iframe
  • 并发调用
  • 双向通信
  • 类 RPC(像本地函数调用一样用)

一、整体架构设计

1)通信拓扑(推荐)

        ┌──────────────┐
        │   主页面     │  ← Broker / 总线
        └─────┬────────┘
              │
    ┌─────────┼─────────┐
    │         │         │
┌───────┐ ┌───────┐ ┌───────┐
│iframeA│ │iframeB│ │iframeC│
└───────┘ └───────┘ └───────┘

👉 核心思想:

  • 主页面 = “消息总线 / Broker”
  • 每个 iframe = 一个“客户端”
  • 所有通信走主页面(避免 iframe 互连复杂性)

2)通信机制

建立连接(一次性)

postMessage + MessageChannel

后续通信

通过 MessagePort(全双工、低开销、不会丢)

二、核心能力设计

你需要实现这几个模块:

模块作用
Connection Manager管理 iframe 连接
RPC Core请求/响应机制
Service Registry函数注册
Router(主页面)转发请求
Promise 管理并发控制

三、通信协议(关键)

{
  "id": "uuid",
  "type": "request | response",
  "method": "getData",
  "params": {},
  "result": {},
  "error": null,
  "from": "iframeA",
  "to": "iframeB"
}

四、完整实现(工业级)


1️⃣ 主页面(Broker)

class IframeBus {
    constructor() {
        this.clients = new Map(); // clientId -> port

        window.addEventListener("message", this._onConnect.bind(this));
    }

    _onConnect(event) {
        const { type, clientId } = event.data || {};
        if (type !== "CONNECT") return;

        const port = event.ports[0];
        this.clients.set(clientId, port);

        port.onmessage = (e) => this._onMessage(clientId, e.data);
    }

    _onMessage(from, msg) {
        const { to } = msg;

        if (!this.clients.has(to)) return;

        this.clients.get(to).postMessage({
            ...msg,
            from
        });
    }
}

👉 初始化:

const bus = new IframeBus();

2️⃣ iframe 客户端 RPC 核心

class IframeRPC {
    constructor(clientId) {
        this.clientId = clientId;
        this.port = null;

        this.handlers = {};
        this.pending = new Map();

        this._connect();
    }

    _connect() {
        const channel = new MessageChannel();

        this.port = channel.port1;

        this.port.onmessage = (e) => {
            this._onMessage(e.data);
        };

        window.parent.postMessage({
            type: "CONNECT",
            clientId: this.clientId
        }, "*", [channel.port2]);
    }

    // 注册服务
    register(method, handler) {
        this.handlers[method] = handler;
    }

    // RPC调用
    call(to, method, params = {}, timeout = 5000) {
        const id = this._uuid();

        return new Promise((resolve, reject) => {
            const timer = setTimeout(() => {
                this.pending.delete(id);
                reject("timeout");
            }, timeout);

            this.pending.set(id, { resolve, reject, timer });

            this.port.postMessage({
                id,
                type: "request",
                method,
                params,
                to
            });
        });
    }

    async _onMessage(msg) {
        if (msg.type === "request") {
            this._handleRequest(msg);
        } else {
            this._handleResponse(msg);
        }
    }

    async _handleRequest(msg) {
        const { id, method, params, from } = msg;

        if (!this.handlers[method]) return;

        try {
            const result = await this.handlers[method](params);

            this.port.postMessage({
                id,
                type: "response",
                result,
                to: from
            });

        } catch (e) {
            this.port.postMessage({
                id,
                type: "response",
                error: e.message,
                to: from
            });
        }
    }

    _handleResponse(msg) {
        const { id, result, error } = msg;

        const pending = this.pending.get(id);
        if (!pending) return;

        clearTimeout(pending.timer);
        this.pending.delete(id);

        error ? pending.reject(error) : pending.resolve(result);
    }

    _uuid() {
        return crypto.randomUUID();
    }
}

五、使用示例


iframe A(调用方)

const rpc = new IframeRPC("A");

rpc.call("B", "getData", { id: 123 })
   .then(res => console.log(res));

iframe B(服务方)

const rpc = new IframeRPC("B");

rpc.register("getData", async (params) => {
    return {
        value: "data from B: " + params.id
    };
});

六、并发能力分析(关键)

这个方案是真正工业级的原因:

✅ 1)天然并发

  • MessagePort 是异步队列
  • 不会阻塞
  • 不会丢消息

✅ 2)请求隔离

  • 每个请求独立 ID
  • Promise Map 管理

✅ 3)性能极高

  • 不走 storage
  • 不序列化多次
  • 不触发全局事件

✅ 4)支持扩展

你可以很容易扩展:

✔ 广播

call("*", "event", data)

✔ 服务发现

bus.registerService("xxx", clientId)

✔ 数据订阅(工业场景关键)

subscribe("sensor-data")

七、对比总结(你这个场景)

方案是否推荐原因
sessionStorage❌不可靠 + 不支持高并发
postMessage⚠️可以,但不够优雅
postMessage + MessageChannel✅最佳实践

八、进一步升级(建议你做)

你现在已经接近:

👉 “浏览器内微服务架构”

下一步建议:

1)加一层 Service Registry

method -> clientId

2)做成:

rpc.call("getDeviceStatus")

而不是指定 B


3)加入数据流(工业系统关键)

实时振动数据
实时功率数据
告警流

用:

Pub/Sub 模型

九、一句话总结

sessionStorage 是“黑科技 hack”,
postMessage + MessageChannel 才是“架构级解法”。


如果你要,我可以直接给你下一版:

👉 “工业互联网 iframe 微前端通信框架(完整版)”

包含:

  • RPC
  • 事件总线
  • 实时数据流(类似 Kafka in Browser)
  • 权限隔离(适合多子系统)

直接说:上工业版 👍

标签: 暂无
最后更新:2026-03-27

阅山

知之为知之 不知为不知

点赞
< 上一篇

COPYRIGHT © 2099 登峰造极境. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

蜀ICP备14031139号-5

川公网安备51012202000587号