跟踪 Javascript eval 中错误的源代码行

发布于 2024-09-15 08:40:33 字数 571 浏览 3 评论 0原文

我正在构建一些包含动态异步 JavaScript 的东西,它可以工作,但我希望改进错误检测(因此所有错误似乎不仅仅来自将它们拉下来的 AJAX 调用附近的某行如果

我使用 eval 来评估多行 javascript 文件,有什么方法可以跟踪发生错误的行吗?

通过保留对包含时所需的变量的引用,我可以毫无问题地确定错误发生在哪个文件中。我的问题是确定错误发生在哪

示例:

try {
  eval("var valid_statement = 7; \n invalid_statement())))");
} catch(e) {
  var err = new Error();
  err.message = 'Error in Evald Script: ' + e.message;
  err.lineNumber = ???
  throw err;
}

我如何判断错误发生在第二行? 具体来说,我对在 Firefox 中执行此操作感兴趣。

我知道错误对象在 Mozilla 浏览器中具有 e.stack,但输出似乎没有正确考虑换行符。

I'm building something that includes javascripts on the fly asynchronously, which works, but I'm looking to improve upon the error detection (so all the errors don't just appear to come from some line near the AJAX call that pulls them down.

If I'm using eval to evaluate a multiline javascript file, is there any way to trace which line an error occurs on?

By keeping references to the variables I need when including, I have no problem determining which file the errors occurs in. My problem is determining which line the error occurs in.

Example:

try {
  eval("var valid_statement = 7; \n invalid_statement())))");
} catch(e) {
  var err = new Error();
  err.message = 'Error in Evald Script: ' + e.message;
  err.lineNumber = ???
  throw err;
}

How can I tell that the error occurred in the second line there?
Specifically I'm interested in doing this in Firefox.

I know that error objects have e.stack in Mozilla browsers, but the output doesn't seem to take into account newlines properly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

垂暮老矣 2024-09-22 08:40:33
  • 评估脚本中的行号从 eval 所在的行号开始。
  • 错误对象具有创建它的行的行号。

所以像...

try {
  eval('var valid_statement = 7; \n invalid_statement())))');
} catch(e) {
  var err = e.constructor('Error in Evaled Script: ' + e.message);
  // +3 because `err` has the line number of the `eval` line plus two.
  err.lineNumber = e.lineNumber - err.lineNumber + 3;
  throw err;
}
  • The line number in an evaled script starts from the one the eval is on.
  • An error object has a line number of the line it was created on.

So something like...

try {
  eval('var valid_statement = 7; \n invalid_statement())))');
} catch(e) {
  var err = e.constructor('Error in Evaled Script: ' + e.message);
  // +3 because `err` has the line number of the `eval` line plus two.
  err.lineNumber = e.lineNumber - err.lineNumber + 3;
  throw err;
}
烦人精 2024-09-22 08:40:33

全局错误事件侦听器将捕获 eval 的异常并显示正确的行号(可能并非在所有浏览器中):

window.addEventListener('error', function(e) {
    console.log(e.message
        , '\n', e.filename, ':', e.lineno, (e.colno ? ':' + e.colno : '')
        , e.error && e.error.stack ? '\n' : '', e.error ? e.error.stack : undefined
    );
}, false);

The global error event-listener will catch the exception from eval and shows the correct line numbers (maybe not in all browsers):

window.addEventListener('error', function(e) {
    console.log(e.message
        , '\n', e.filename, ':', e.lineno, (e.colno ? ':' + e.colno : '')
        , e.error && e.error.stack ? '\n' : '', e.error ? e.error.stack : undefined
    );
}, false);
冰之心 2024-09-22 08:40:33

我不认为你可以用 eval 可靠地做到这一点。但是,您可以这样做而不是 eval:

try {
    $("<script />").html(scriptSource).appendTo("head").remove();
} catch (e) {
    alert(e.lineNumber);
}

I don't think you can do it with eval reliably. However, you can do this instead of eval:

try {
    $("<script />").html(scriptSource).appendTo("head").remove();
} catch (e) {
    alert(e.lineNumber);
}
大海や 2024-09-22 08:40:33

加入 window.addEventListener('error', ...)document.createElement('script') 对我有用:

window.addEventListener('error', function(e) {
  console.log('Error line:', e.lineno)
}, false);  

function runCode (code) {
  let js = document.createElement('script')
  try {
    js.innerHTML = code
    document.head.appendChild(js)
  }
  catch(e) {
    // ...
  }
  document.head.removeChild(js)
}

runCode('// try this:\n1ss') // prints 'Error line: 2'

感谢 @frederic-leitenberger 和 @fromin对于解决方案部分。

Join the window.addEventListener('error', ...) with document.createElement('script') works for me:

window.addEventListener('error', function(e) {
  console.log('Error line:', e.lineno)
}, false);  

function runCode (code) {
  let js = document.createElement('script')
  try {
    js.innerHTML = code
    document.head.appendChild(js)
  }
  catch(e) {
    // ...
  }
  document.head.removeChild(js)
}

runCode('// try this:\n1ss') // prints 'Error line: 2'

Thanks to @frederic-leitenberger and @fromin for the solutions parts.

若言繁花未落 2024-09-22 08:40:33

令人烦恼的事实是,当您使用 eval() 或 new Function() 时,只有全局错误处理程序才会获取详细的脚本解析错误。如果错误被任何异常处理程序捕获,则即使处理程序重新抛出错误,也无法恢复详细信息。因此,您必须以某种方式安排在任何异常处理程序的范围之外执行 eval。

在 Firefox 上,我必须修改配置设置,以便它能够在本地 HTML 文件中执行脚本。 Firefox 在列号上也略有不同,但这很可能只是解析器前瞻的变幻莫测。除此之外,输出基本相同。我使用更通用的“new Function”,而不是直接调用 eval()。

我使用最新 (05/26/2023) 版本的 Firefox/Chrome/Edge 测试了此脚本:

<html>
<head>
</head>
<body>BODY</body>
<script>
 function errorHandler(e){
     const {lineno,colno} = event;
     let line = script1.split('\n')[lineno-3];
     console.log(line);
     let marker = "-".repeat(colno-1)+"^";
     console.log(marker);
     console.log(event.message);
     return true; // allow execution to continue
 }
 window.addEventListener('error', errorHandler, true);
 let script1 = "let x = 5;\nx=.x;\n";
 let script2 = "let y = 5;\ny=.y;\n";
 let func;
 func    = new Function(script1);
 try {
     func    = new Function(script2);
 }catch(e){
     console.log(e);
 }
</script>

输出如下所示:

如您所见,全局错误处理程序获取一个具有足够丰富的属性集的事件,它可以显示详细信息(包括相关行的文本,如果它有权访问脚本文本 )。异常处理程序仅获取不太有用的预装消息。

将脚本复制到“脚本”节点并将其临时插入文档头怎么样?您无法获得使用“新功能”所获得的控制权。例如,我想像节点模块一样对待我的可加载脚本。通过使用“函数”,我既可以将信息传递给脚本(例如它可以调用“require”函数来提供对其他信息的受控访问),也可以获取信息(脚本的最后一个表达式是执行新创建的函数)。

当然,您可以使用全局变量来绕过这些限制,并且真正将 eval() 编辑的脚本放在沙箱中是相当不可能的,但是由于 JavaScript 中的范围如此无限,我更喜欢控制范围,以便 eval() 编辑的脚本能够充分控制范围。极不可能不小心踩到其他东西。

编辑 23 年 5 月 27 日:
忘记实际测试插入脚本节点技巧。在所有三种浏览器上,它不提供详细的错误信息。因此,AFAICT,从动态脚本获取详细错误信息的唯一方法是使用 eval() 或 new Function,并确保错误到达全局错误处理程序而不被异常处理程序捕获。

The annoying fact is that only the global error handler will get the detailed script parsing errors when you use eval() or new Function(). If the error is caught by any exception handler, then there is no way to recover the detailed information, even if the handler re-throws it. So, you have to somehow arrange to execute your eval outside the scope of any of your exception handlers.

On Firefox, I had to diddle config settings so it would execute scripts in a local HTML file. Firefox also disagreed slightly on the column number, but that's likely just the vagaries of parser lookahead. Other than that, the outputs were essentially identical. I use the more general "new Function" rather than directly calling eval().

I tested this script with the latest (05/26/2023) versions of Firefox/Chrome/Edge:

<html>
<head>
</head>
<body>BODY</body>
<script>
 function errorHandler(e){
     const {lineno,colno} = event;
     let line = script1.split('\n')[lineno-3];
     console.log(line);
     let marker = "-".repeat(colno-1)+"^";
     console.log(marker);
     console.log(event.message);
     return true; // allow execution to continue
 }
 window.addEventListener('error', errorHandler, true);
 let script1 = "let x = 5;\nx=.x;\n";
 let script2 = "let y = 5;\ny=.y;\n";
 let func;
 func    = new Function(script1);
 try {
     func    = new Function(script2);
 }catch(e){
     console.log(e);
 }
</script>

The outputs looked like this:
enter image description here

As you can see, the global error handler gets an event with a rich enough set of properties that it can display detailed information (including the text of the relevant line, if it has access to the script text). The exception handler only gets the less helpful pre-canned message.

What about copying the script to a 'script' node and temporarily inserting it into the document head? You don't get the control you get by using 'new Function'. For example, I want to treat my loadable scripts much like node modules. By using 'Function', I can both pass in information to the script (such as a 'require' function it can call to give controlled access to other information) and get information back (the last expression of the script is the return value of executing the newly created function).

Of course, you can hack around these limitations with global variables and it's fairly impossible to truly sandbox an eval()'ed script, but with such infinite scopes in JavaScript, I prefer to control the scope enough that the eval()'ed script is extremely unlikely to accidentally tread on anything else.

Edit 05/27/23:
Forgot to actually test the insert-script-node trick. On all three browsers, it does not provide detailed error info. So, AFAICT, the only way to get detailed error info from a dynamic script is to use eval() or new Function, and make sure the error gets to the global error handler without being caught with an exception handler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文