UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

227 lines (220 loc) 7.32 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const uuid_1 = require('uuid'); /** * 用于两个 window 之间通信 * 除了基本的发送消息,提供了如命令式等更多方法 */ class Messager { options; requests; constructor(options) { this.options = Object.assign({ protocol: 'vusion', sender: 'platform', logLevel: 'info', timeout: 30000, onlySend: false, getSender() { return window.parent; }, getReceiver() { return window; }, handleMessage(message) { // handle }, }, options); this.requests = new Map(); this.onMessageReceived = this.onMessageReceived.bind(this); this.onDataReceived = this.onDataReceived.bind(this); if (!this.options.onlySend) { const receiver = this.options.getReceiver.call(this.options.context); if (receiver.addEventListener) receiver.addEventListener('message', this.onMessageReceived); else if (receiver.addListener) receiver.addListener('message', this.onDataReceived); } } destroy() { !this.options.onlySend && this.options.getReceiver.call(this.options.context).removeEventListener('message', this.onMessageReceived); } /** * 发送信息 * 所有下面方法的基础方法 * 比较原生,直接给目标 window 中 postMessage */ sendMessage(message) { const logLevel = message.logLevel || this.options.logLevel; if (logLevel === 'info') { // const str = JSON.stringify(message); // console.info(`[messager]`, str); } const sender = this.options.getSender.call(this.options.context); if (typeof window !== 'undefined' && sender instanceof Window) sender.postMessage(message, '*'); else sender.postMessage(message); } /** * 发送数据 * 包装了协议和发送者。Window 的 message 可能来自不同地方,统一格式区分。 * @param data 数据 */ sendData(data) { return this.sendMessage({ protocol: this.options.protocol, sender: this.options.sender, type: 'send', data, }); } /** * 发送命令 * 直接发送一个命令 * 包装了协议和发送者。Window 的 message 可能来自不同地方,统一格式区分。 * @param command 命令名 * @param args 参数 */ sendCommand(command, ...args) { return this.sendMessage({ protocol: this.options.protocol, sender: this.options.sender, type: 'send', command, args, }); } /** * 请求信息 * 与 send 系列的区别是接收返回数据 */ requestMessage(message, options) { if (options) { Object.assign(message, options); } this.sendMessage(message); return new Promise((res, rej) => { const timeoutTimer = setTimeout(() => { this.requests.delete(message.id); rej(Object.assign({ error: 'Timeout' }, message)); }, this.options.timeout || 2000); const resolve = (data) => { // 需要主动把定时器卸载掉,避免内存泄露 this.requests.delete(message.id); clearTimeout(timeoutTimer); res(data); }; const reject = (e) => { // 需要主动把定时器卸载掉,避免内存泄露 this.requests.delete(message.id); clearTimeout(timeoutTimer); rej(e); }; this.requests.set(message.id, Object.assign({ res: resolve, rej: reject }, message)); }); } /** * 请求数据 * 与 sendData 系列的区别是接收返回数据 */ requestData(data) { const message = { id: (0, uuid_1.v4)(), protocol: this.options.protocol, sender: this.options.sender, type: 'request', data, }; return this.requestMessage(message); } /** * 请求命令 * 与 sendCommand 系列的区别是接收返回数据 */ requestCommand(command, ...args) { const message = { id: (0, uuid_1.v4)(), protocol: this.options.protocol, sender: this.options.sender, type: 'request', command, args, }; return this.requestMessage(message); } /** * 内置处理接收的 MessageEvent 事件 * @override */ onMessageReceived(e) { if (!e.data) return; this.onDataReceived(e.data); } count = 0; /** * 内置处理接收的数据 * @override */ onDataReceived(data) { this.count++; if (this.count === 5) { this.count = 0; // 预留时间做 minor gc,减少峰值内存占用 (async () => await new Promise(resolve => setTimeout(resolve, 30)))(); } if (data.protocol !== this.options.protocol) return; if (data.type === 'response') { const message = this.requests.get(data.id); if (message) { message.error ? message.rej(data.error) : message.res(data.result); } return; } if (data.command) { const func = this.options.context[data.command]; if (!func) // 函数不存在时不 response return; let res; if (typeof func === 'function') { res = func.call(this.options.context, ...data.args, data.id); } else { res = func; } if (data.type === 'request') { return Promise.resolve(res) .then((result) => { this.sendMessage({ id: data.id, protocol: this.options.protocol, sender: this.options.sender, logLevel: data.logLevel, type: 'response', command: data.command, result, }); }) .catch((error) => { console.error(error); this.sendMessage({ id: data.id, protocol: this.options.protocol, sender: this.options.sender, logLevel: data.logLevel, type: 'response', command: data.command, error, }); }); } else { return; } } this.options.handleMessage(data); } } exports.default = Messager; //# sourceMappingURL=Messager.js.map