/* ============================================================================
* WorkBus.js — Promise 通信总线(ES6 模块,Node / 浏览器双端)
*
* 通信模式:resolve / waitEnd(Promise 握手)
* - WorkBus.resolve(event, payload) 发布(解决)事件:缓存最后 payload,唤醒全部等待者
* - WorkBus.waitEnd(event, [timeout]) 等待事件:已解决立即返回缓存值;
* 否则挂起,直到被 resolve 唤醒;可带超时
* - 时序无关:先 resolve 后 waitEnd → 命中缓存立即返回;
* 先 waitEnd 后 resolve → 挂起等待、发布时唤醒
* - 无 Node 专属依赖,Node / 浏览器通用(仅默认导出)
*
* 用法(Node):
* import WorkBus from "./WorkBus.js";
* 用法(浏览器):
* <script type="module">
* import WorkBus from "./WorkBus.js";
* </script>
*
* WorkBus.resolve("init", { verbose: 1 });
* const res = await WorkBus.waitEnd("init");
* ========================================================================== */
/* 事件名 -> { resolved, payload, waiters: Set<{resolve, reject, timer}> } */
const states = new Map();
function getState(event) {
if (!states.has(event)) {
states.set(event, { resolved: false, payload: undefined, waiters: new Set() });
}
return states.get(event);
}
/**
* 发布(解决)事件:缓存最后 payload,唤醒所有 waitEnd 等待者。
* @param {string} event 事件名(非空字符串)
* @param {*} payload 负载数据
*/
function resolve(event, payload) {
if (typeof event !== "string" || event.length === 0) {
throw new TypeError("[WorkBus] resolve: event 必须是非空字符串");
}
const st = getState(event);
st.resolved = true;
st.payload = payload;
for (const w of st.waiters) {
if (w.timer) clearTimeout(w.timer);
w.resolve(payload);
}
st.waiters.clear();
}
/**
* 等待事件:已 resolve 过则立即返回缓存值,否则挂起等待下一次 resolve。
* @param {string} event 事件名
* @param {number} [timeout] 超时毫秒;缺省或 <=0 表示永不超时
* @returns {Promise<*>} payload;超时则 reject
*/
function waitEnd(event, timeout) {
if (typeof event !== "string" || event.length === 0) {
throw new TypeError("[WorkBus] waitEnd: event 必须是非空字符串");
}
const st = getState(event);
if (st.resolved) return Promise.resolve(st.payload);
return new Promise((resolve, reject) => {
const w = { resolve, reject, timer: null };
st.waiters.add(w);
if (typeof timeout === "number" && timeout > 0) {
w.timer = setTimeout(() => {
st.waiters.delete(w);
reject(new Error(`[WorkBus] 等待事件 "${event}" 超时(${timeout}ms)`));
}, timeout);
}
});
}
const WorkBus = { resolve, waitEnd };
export default WorkBus;
/* ============================================================================
* 使用例子:node WorkBus.js 直接运行即自测;浏览器加载或被 import 时不执行
* ① "init" 先 resolve 后 waitEnd → 命中缓存,立即返回
* ② "getConfig" 先 waitEnd 后 resolve → 挂起等待,1s 后发布唤醒
* ========================================================================== */
// WorkBus.resolve("init", { verbose: 1 }); // 先发布 → 缓存
// setTimeout(function () {
// WorkBus.resolve("getConfig", { verbose: 2 }); // 1s 后发布,唤醒 main()
// }, 1000);
// setTimeout(function () {
// WorkBus.resolve("getConfig", { verbose: 3 }); // 2s 后再次发布:仅更新缓存(此时已无等待者)
// }, 2000);
//
// async function main() {
// const res = await WorkBus.waitEnd("init"); // 已有缓存 → 立即返回
// console.log(res);
// const res2 = await WorkBus.waitEnd("getConfig"); // 尚未发布 → 挂起等待,1s 后被唤醒
// console.log(res2);
// const res3 = await WorkBus.waitEnd("getConfig"); // 已发布 → 命中缓存,立即返回
// console.log(res3);
// }
// main();