【问题标题】:Eval String of Javascript with Line and Column Offset?带有行和列偏移的Javascript的评估字符串?
【发布时间】:2016-04-04 12:27:06
【问题描述】:

有谁知道评估字符串的方法,以便如果它(或它定义的函数)产生错误,堆栈跟踪中显示的行号和列号将被预先指定的数量偏移? 或者,假设我想将一个长的源字符串分成多个块并分别评估它们,但仍然获得看起来好像整个字符串都被一次性评估的堆栈跟踪。除了使用空行和空列之外,有什么方法可以达到这种效果? (我需要一个基于浏览器的解决方案,最好是跨浏览器,但我可以满足于至少在一个主要浏览器上工作的东西。)

【问题讨论】:

  • 可能源图是要走的路,但我不知道它们是否适用于eval
  • 我认为源映射必须由将块连接成单个字符串以进行评估的工具生成,但我特别需要单独评估块,因为在某个块中定义的函数可能在生成以后的块的过程中使用。
  • 你为什么要这样做?
  • 我有一种自定义编程语言,可以编译成 javascript 的子集。它有一个 lispy 宏系统,因此可以在任何给定点定义一个宏并在后续代码中使用它,这意味着它必须在其他任何事情之前进行评估。更糟糕的是,宏还可以使用先前定义的普通函数,因此必须在宏之前对它们进行评估。问题是堆栈跟踪中的源位置以这种方式变得无用,因为它们重叠,我无法明确地将它们映射回原始源代码。
  • 如果您不需要同步,则将代码转换为数据/blob URL 并将其添加为脚本标签将允许错误消息显示正确的行号和列号,不像一个原始的eval

标签: javascript eval


【解决方案1】:

我认为这不可能,因为假定工作的底层机制实际上是deprecated。出于安全原因,浏览器不再将错误对象传递给 Javascript。

但是,由于您使用的是编译成 Javascript 的自定义编程语言,因此您知道生成的脚本的结构。您还可以在生成的 Javascript 中引入语句计数器,因此您始终可以知道最后执行的操作是什么。比如:

function(1); function(2);
function(3);

可以翻译为:

var __column=0;
var __line=0;
function(1); __column+=12;
function(2); /*__column+=12;*/ __line++; __column=0;
function(3); /*__column+=12;*/ __line++; __column=0;

其中 12 是 "function(n);".length。当然,生成的代码很难看,但您可以使用调试标志或其他东西启用此行为。

【讨论】:

  • 可以获得错误对象,但是当提供的行/列对不是唯一的时,这并没有真正的帮助。 (而且它们不是,因为我分别评估了许多代码块。)我感兴趣的是以某种方式告诉 JS 引擎生成一个合适的堆栈跟踪开始。例如,这在 NodeJS 中使用它的 vm 模块是可能的,我正在寻找一种在浏览器上做同样事情的方法。
  • 对于建议的解决方案,执行的最后一个位置本身并不是特别有用,所以无论从哪里输入/返回函数,我都必须维护它们的堆栈。我还必须使用临时变量来展平 a(b(c)) 甚至 a+b+c 之类的东西。每个操作都有很多样板,这对于我的主要用例(游戏开发)来说是不可取的。即使我可以忍受开发过程中的性能损失,我也会在部署的产品中关闭此功能,因此用户发生的任何错误都很难调试。
【解决方案2】:

到目前为止,我发现的最佳解决方案是在每个字符串被 eval 之前为其添加一个 sourceURL 指令,从而在堆栈跟踪中以唯一文件名的形式为其提供一个标记。然后解析堆栈跟踪(使用解析器组件 stacktracejs)并通过查找与标记关联的行偏移来进行更正。

var evalCounter = 0;
var lineCounter = 0;
var lineOffsetTable = {};

    function myEval(code) {
      lineOffsetTable[evalCounter] = lineCounter;
      lineCounter += countLines(code);
      return eval("//# sourceURL=" + (evalCounter++) + "\n" + code);
    }

    window.onerror = function(errorMsg, url, lineNumber, column, e) {
      var stackFrames = ErrorStackParser.parse(e);
      logStackTrace(stackFrames.map(function(f) {
         if(f.fileName in lineOffsetTable)
            f.lineNumber += lineOffsetTable[f.fileName];
         return f;
      }));
    };

不幸的是,目前这只适用于 Firefox。 Chrome 拒绝将错误对象传递给 onerror 回调(奇怪的是,这个问题只发生在经过评估的代码中)并且 IE 忽略了 sourceURL 指令。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-11
    • 1970-01-01
    • 2015-10-13
    相关资源
    最近更新 更多