如何挂起room.onPlayerChat事件等待XMLHttpRequest请求完成后执行后续逻辑
问题核心原因
room.onPlayerChat 本身是同步回调逻辑,框架会同步读取回调的返回值判断是否要阻止默认的消息发送行为。你将回调设置为async函数后,代码里写的return false会被自动包装为Promise对象返回,框架读取到非布尔值false,就会直接触发默认的普通消息发送,不会等待你的异步校验请求执行完成。
解决方案
完全接管聊天消息的发送逻辑,默认拦截所有事件的默认发送行为,等异步校验完成后手动发送对应格式的消息:
- 外层使用普通同步函数,直接返回
false阻止框架默认发送 - 异步校验逻辑放在自执行的async函数块内,校验完成后手动调用发送接口
- 补充普通玩家的消息发送逻辑,避免普通玩家消息丢失
修正后代码如下:
const makeRequest = (method, url, data = {}) => { const xhr = new XMLHttpRequest(); return new Promise(resolve => { xhr.open(method, url, true); xhr.onload = () => resolve({ status: xhr.status, response: xhr.responseText }); xhr.onerror = () => resolve({ status: xhr.status, response: xhr.responseText }); if (method != 'GET') xhr.setRequestHeader('Content-Type', 'application/json'); Object.keys(data).length ? xhr.send(JSON.stringify(data)) : xhr.send(); }) } // 新增手动发送标记,避免递归触发onPlayerChat导致死循环 let isManualSend = false; // 可选:新增角色缓存,减少重复请求 const playerRoleCache = new Map(); room.onPlayerChat = function (player, message) { // 手动发送的消息直接放行,不重复处理 if (isManualSend) return true; // 同步直接返回false,阻止框架默认发送逻辑 (async () => { let isAdmin = false; // 优先读缓存 if (playerRoleCache.has(player.name)) { isAdmin = playerRoleCache.get(player.name); } else { const request = await makeRequest("GET", 'URL/TO/CHECK/PLAYER/ADMIN/ROLE' + player.name); isAdmin = request.response === "YES"; // 写入缓存,下次不用重复请求 playerRoleCache.set(player.name, isAdmin); } // 手动发送消息 isManualSend = true; if (isAdmin) { room.sendmessage("ADMIN" + player.name + message); } else { room.sendmessage(player.name + message); } isManualSend = false; })(); return false; }
注意事项
如果玩家角色会动态变更,可以给缓存加过期时间,定期清理过期的角色校验结果,避免角色变更后消息显示异常。
内容的提问来源于stack exchange,提问作者Abanob Gerges
相关产品推荐
相关产品推荐

