import LocalStorageEvent from "./localStorageEvent"; class LocalStorageEmitter { namespace = "wfc-"; /** * * @type {Map} */ subscriptions; /** * * @type {Map} */ handles; /** * * @type {Map} */ invokes; constructor() { window.__lse = this; window.addEventListener("storage", (ev) => { let key = ev.key; if (!key) { return; } if (!key.startsWith(this.namespace + "$") || !key.endsWith("$")) { return; } let value; try { value = JSON.parse(ev.newValue); } catch (e) { value = null; } if (value === null) { console.log("localStorageEmitter ignore null", key); return; } if (key.endsWith("$r$")) { this.invokes.forEach((invoke, k) => { let invokeReturnValueKey = k + "r" + "$"; if (invokeReturnValueKey === key) { invoke.callback(value.r); let b = this.invokes.delete(k); localStorage.removeItem(invokeReturnValueKey); localStorage.removeItem(k); } }); } else { this.subscriptions.forEach((subscription, k) => { if (k === key) { subscription.listener(new LocalStorageEvent(this), value.args); if (subscription.once) { this.subscriptions.delete(k); } localStorage.removeItem(k); } }); this.handles.forEach((handle, k) => { if (key.indexOf("$$") === -1 || key.indexOf("$r$") > -1) { return; } let index = key.indexOf("$$"); let invokeKey = key.substr(0, index + 1); if (k === invokeKey) { let invokeId = value.invokeId; let returnValue = handle.listener(new LocalStorageEvent(this), value.args); let invokeReturnValueKey = k + "$" + invokeId + "$" + "r" + "$"; if (returnValue instanceof Promise) { returnValue .then((v) => { let r = { r: v }; localStorage.setItem(invokeReturnValueKey, JSON.stringify(r)); }) .catch((reason) => { console.log("handle failed", reason); }); if (handle.once) { this.handles.delete(k); } } else { let r = { r: returnValue }; console.log("handle res", invokeId, returnValue); localStorage.setItem(invokeReturnValueKey, JSON.stringify(r)); if (handle.once) { this.handles.delete(k); } } localStorage.removeItem(invokeKey); } }); } }); this.subscriptions = new Map(); this.handles = new Map(); this.invokes = new Map(); } /** * 订阅通知 * @param {string} channel * @param {function(LocalStorageEvent, args)} listener */ on(channel, listener) { this.subscriptions.set(this.namespace + "$" + channel + "$", { once: false, listener: listener }); } /** * 一次性订阅 * @param {string} channel * @param {function(LocalStorageEvent, args)} listener */ once(channel, listener) { this.subscriptions.set(this.namespace + "$" + channel + "$", { once: true, listener: listener }); } /** * 发布通知 * @param {string} channel * @param {any} args */ send(channel, args) { let tmp = { args: args }; localStorage.setItem(this.namespace + "$" + channel + "$", JSON.stringify(tmp)); } // // sendSync(channel, args) { // this.send(channel, args); // } /** * 处理远程调用 * @param {string} channel * @param {function (any)} listener */ handle(channel, listener) { this.handles.set(this.namespace + "$" + channel + "$", { once: false, listener: listener }); } /** * 一次性处理远程调用 * @param {string} channel * @param {function (any)} listener */ handleOnce(channel, listener) { this.handles.set(this.namespace + "$" + channel + "$", { once: true, listener: listener }); } /** * 执行远程调用,调用结果通过callback回调 * @param {string} channel * @param {any} args * @param {function (any)} callback */ invoke(channel, args, callback) { let invokeId = new Date().getTime() + "-" + Math.ceil(Math.random() * 10000); this.invokes.set(this.namespace + "$" + channel + "$$" + invokeId + "$", { invokeId: invokeId, callback: callback, }); let tmp = { invokeId: invokeId, args: args, }; localStorage.setItem(this.namespace + "$" + channel + "$$" + invokeId + "$", JSON.stringify(tmp)); } /** * 执行远程调用,调用结果通过promise返回 * @param channel * @param args * @return {Promise} */ promiseInvoke(channel, args) { return new Promise((resolve, reject) => { this.invoke(channel, args, (v) => { resolve(v); }); }); } _dump() { console.log("dump localStorageEmitter"); this.subscriptions.forEach((value, key) => { console.log(key, value); }); this.handles.forEach((value, key) => { console.log(key, value); }); this.invokes.forEach((value, key) => { console.log(key, value); }); } } let self = new LocalStorageEmitter(); export default self;