When creating new function from JavaScript code using new Function(params,body) constructor, passing invalid string in body yelds SyntaxError. While this exception contains error message (ie: Unexpected token =
), but does not seem to contain context (ie. line/column or character where error was found).
Example fiddle: https://jsfiddle.net/gheh1m8p/
var testWithSyntaxError = "{\n\n\n=2;}";
try {
var f=new Function('',testWithSyntaxError);
} catch(e) {
console.log(e instanceof SyntaxError);
console.log(e.message);
console.log(e.name);
console.log(e.fileName);
console.log(e.lineNumber);
console.log(e.columnNumber);
console.log(e.stack);
}
输出:
true
(index):54 Unexpected token =
(index):55 SyntaxError
(index):56 undefined
(index):57 undefined
(index):58 undefined
(index):59 SyntaxError: Unexpected token =
at Function (native)
at window.onload (https://fiddle.jshell.net/_display/:51:8)
在不使用外部依赖项的情况下,如何在传递的字符串中精确定位SyntaxError位置?我需要浏览器和nodejs的解决方案。
请注意:我确实有理由使用等效代码。
浏览器解决方案:
您可以使用最新的Firefox在字符串中获取所需的信息,例如错误行号和列号。
例:
Firefox控制台中的输出:
其中6是行号,1是字符串内部错误的列号。
在Chrome中无法使用。 chrome浏览器存在有关此问题的错误。看到:
https://bugs.chromium.org/p/v8/issues/detail?id=1281
https://bugs.chromium.org/p/v8/issues/detail?id=1914
https://bugs.chromium.org/p/v8/issues/detail?id=2589
我正在总结评论和一些其他研究:
简单的答案:目前不可能
There is currently no cross-platform way to retrive syntax error position from
new Function()
oreval()
call.部分解决方案
error.lineNumber
anderror.e.columnNumber
. This can be used with feature detection if position of error is not critical.解决方案1和2不完整,依赖于不属于标准的功能。如果此信息是帮助而不是要求,那么它们可能是合适的。
解决方案3取决于外部代码库,这是原始问题明确要求的。如果需要此信息,并且可以接受较大的代码库,则比较合适。
解决方案4是不切实际的。
鸣谢:@ user3896470,@ ivan-kuckir,@ aprillion
In Chromium-based browsers, as you've seen, putting
try
/catch
around something that throws a SyntaxError while V8 is parsing the code (before actually running it) won't produce anything helpful; it will describe the line that caused the evaluation of the problematic script in the stack trace, but no details on where the problem was in said script.But, there's a cross-browser workaround. Instead of using
try
/catch
, you can add anerror
listener towindow
, and the first argument provided to the callback will be anErrorEvent
which has usefullineno
andcolno
properties:在浏览器控制台中检查结果:
这就是我们想要的!字符20对应于
且字符5对应于
There are a couple issues, though: it would be good to make sure in the
error
listened for is an error thrown when runningcheckSyntax
. Also,try
/catch
can be used for runtime errors (including syntax errors) after the script text has been parsed into an AST by the interpreter. So, you might havecheckSyntax
only check that the Javascript is initially parsable, and nothing else, and then usetry/catch
(if you want to run the code for real) to catch runtime errors. You can do this by insertingthrow new Error
to the top of the text that'seval
ed.这是一个方便的基于Promise的函数,可以完成此任务:
结果:
If the fact that an error is thrown at
window
is a problem (for example, if something else is already listening for window errors, which you don't want to disturb, and you can't attach your listener first and callstopImmediatePropagation()
on the event), another option is to use a web worker instead, which has its own execution context completely separate from the originalwindow
:Essentially, what
checkSyntax
is doing is checking to see if the code provided can be parsed into an Abstract Syntax Tree by the current interpreter. You can also use packages like @babel/parser or acorn to attempt to parse the string, though you'll have to configure it for the syntax permitted in the current environment (which will change as new syntax gets added to the language).The above works for browsers. In Node, the situation is different: listening for an uncaughtException can't be used to intercept the details of syntax errors, AFAIK. However, you can use vm module to attempt to compile the code, and if it throws a SyntaxError before running, you'll see something like this. Running
导致一堆
So, just look at the first item in the stack to get the line number, and at the number of spaces before the
^
to get the column number. Using a similar technique as earlier, throw an error on the first line if parsing is successful:结果:
说:
除非您必须在没有外部库的情况下实现此目标,否则使用库确实是最简单(且经过反复测试)的解决方案。如前面所示(和其他解析器),橡子也可以在Node中工作。