UNPKG

@ticatec/iframe-message-bridge

Version:

A lightweight TypeScript library for reliable communication between parent window and multiple iframes using postMessage, supporting one-way messages, request-response patterns, broadcast messaging, timeout handling, and automatic resource cleanup.

116 lines (115 loc) 3.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MessageBridgeClient = void 0; class MessageBridgeClient { constructor(targetOrigin) { this.pending = new Map(); this.broadcastHandlers = new Map(); this.requestId = 0; this.targetOrigin = targetOrigin; this.boundHandleMessage = this.handleMessage.bind(this); window.addEventListener('message', this.boundHandleMessage); } handleMessage(event) { if (event.origin !== this.targetOrigin) return; const { data } = event; if (!data || data.__bridge__ !== true) return; // 处理响应消息 if (data.type === 'response') { const message = data; const { requestId, result, error } = message; const pending = this.pending.get(requestId); if (pending) { if (error) pending.reject(new Error(error)); else pending.resolve(result); this.pending.delete(requestId); } } // 处理广播消息 if (data.type === 'broadcast') { const message = data; const { eventName, data: broadcastData } = message; const handler = this.broadcastHandlers.get(eventName); if (handler) { handler(broadcastData); } } } // 发送请求并等待响应 emit(eventName, data, timeout = 30000) { const requestId = `req_${Date.now()}_${++this.requestId}`; const message = { __bridge__: true, type: 'request', requestId, eventName, data, }; window.parent.postMessage(message, this.targetOrigin); return new Promise((resolve, reject) => { // 设置超时处理 const timeoutId = setTimeout(() => { if (this.pending.has(requestId)) { this.pending.delete(requestId); reject(new Error(`Request timeout after ${timeout}ms for event: ${eventName}`)); } }, timeout); this.pending.set(requestId, { timeoutId, resolve: (result) => { clearTimeout(timeoutId); resolve(result); }, reject: (error) => { clearTimeout(timeoutId); reject(error); } }); }); } // 发送单向消息(不等待响应) send(eventName, data) { // 使用 null 作为 requestId 表示不需要响应 const message = { __bridge__: true, type: 'request', requestId: null, eventName, data, }; window.parent.postMessage(message, this.targetOrigin); } // 注册广播消息处理器 onBroadcast(eventName, handler) { this.broadcastHandlers.set(eventName, handler); } // 取消注册广播消息处理器 offBroadcast(eventName) { this.broadcastHandlers.delete(eventName); } // 清空所有广播消息处理器 clearBroadcastHandlers() { this.broadcastHandlers.clear(); } // 清空所有待处理的请求(拒绝所有等待中的Promise) clearPendingRequests() { this.pending.forEach(({ reject, timeoutId }) => { if (timeoutId) { clearTimeout(timeoutId); } reject(new Error('Request cancelled - client destroyed')); }); this.pending.clear(); } // 销毁实例,移除全局监听器并清理所有资源 destroy() { window.removeEventListener('message', this.boundHandleMessage); this.clearPendingRequests(); this.clearBroadcastHandlers(); } } exports.MessageBridgeClient = MessageBridgeClient;