如何跨浏览器识别抛出错误的匿名Function实例对应的代码来源
可行跨浏览器解决方案
方案1:使用sourceURL标记每个玩家的函数(推荐)
这是目前兼容性最好、实现成本最低的方案,原理是通过JS内置的源映射注释为每个Function实例分配唯一标识,所有主流浏览器都会在错误栈、window.onerror回调的source参数中携带该标识,不会影响原有行号的获取。
实现步骤:
- 生成玩家函数时,在代码末尾追加唯一的
sourceURL注释,标识中携带玩家ID/函数ID:
// 示例:玩家ID为123的代码 const playerCode = `// 玩家提交的原始代码 const a = 1; console.log(x); //# sourceURL=player-fn-123.js`; const playerFn = new Function(playerCode);
- 在
window.onerror回调中直接从source参数提取标识即可判断归属:
window.onerror = function(message, source, lineno, colno, error) { // source会返回你设置的"player-fn-123.js",提取123即可拿到对应玩家ID const playerId = source.match(/player-fn-(\d+)\.js/)?.[1]; // lineno还是原始错误行号,不受影响 }
该方案在Chrome、Firefox、Safari等所有主流浏览器中均生效,不需要解析错误栈,和你现有获取行号的逻辑完全兼容。
方案2:使用闭包绑定上下文(备选)
如果你不能修改玩家提交的代码内容,可以为每个玩家函数生成一个独立的闭包包装器,在闭包内存储对应的玩家ID,当错误触发时,直接给原始错误对象挂载自定义标识即可:
function wrapPlayerFn(fn, playerId) { return function() { try { return fn.apply(this, arguments); } catch (e) { // 给错误对象挂载自定义属性 e._playerId = playerId; // 直接抛出原始错误,不要重新封装Error对象,避免修改行号 throw e; } } }
之后在window.onerror回调中直接读取error._playerId即可,该操作不会修改原始错误的行号信息,Chrome、Firefox均兼容。
内容的提问来源于stack exchange,提问作者Gillespie
相关产品推荐
相关产品推荐

