教程:在执行调试器语句时计算表达式

**注意:本教程在当前版本的 Firefox 中不再有效。** 请改用更新和扩展的 断点教程

此页面展示了如何使用 Firefox 的 Scratchpad 自己尝试 Debugger API。我们使用 API 在网页每次执行 JavaScript debugger; 语句时计算表达式。

  1. 访问 URL about:config,并将 devtools.chrome.enabled 首选项设置为 true

    Setting the 'devtools.chrome.enabled' preference

  2. 将以下 HTML 文本保存到文件,并在浏览器中访问该文件

    <div onclick="var x = 'snoo'; debugger;">Click me!</div>
    
  3. 打开开发者 Scratchpad(菜单按钮 > 开发者 > Scratchpad),并从“环境”菜单中选择“浏览器”。(除非您已如上所述更改首选项,否则此菜单将不会出现。)

    Selecting the 'browser' context in the Scratchpad

  4. 在 Scratchpad 中输入以下代码

    // This simply defines 'Debugger' in this Scratchpad;
    // it doesn't actually start debugging anything.
    const { addDebuggerToGlobal } = ChromeUtils.importESModule(
      "resource://gre/modules/jsdebugger.sys.mjs"
    );
    addDebuggerToGlobal(window);
    
    // Create a 'Debugger' instance.
    var dbg = new Debugger;
    
    // Get the current tab's content window, and make it a debuggee.
    var w = gBrowser.selectedBrowser.contentWindow.wrappedJSObject;
    dbg.addDebuggee(w);
    
    // When the debuggee executes a 'debugger' statement, evaluate
    // the expression 'x' in that stack frame, and show its value.
    dbg.onDebuggerStatement = function (frame) {
        alert('hit debugger statement; x = ' + frame.eval('x').return);
    }
    
  5. 在 Scratchpad 中,确保未选中任何文本,然后按“运行”按钮。

  6. 现在,点击网页中显示的“点击我!”文本。这将运行 div 元素的 onclick 处理程序。当控制权到达 debugger; 语句时,Debugger 调用您的回调函数,并传递一个 Debugger.Frame 实例。您的回调函数在给定的栈帧中计算表达式 x,并显示警报

    The Debugger callback displaying an alert

  7. 再次按 Scratchpad 中的“运行”。现在,点击“点击我!”文本将导致显示两个警报——每个 Debugger 实例一个。

    多个 Debugger 实例可以观察同一个被调试对象。在 Scratchpad 中重新运行代码创建了一个新的 Debugger 实例,将同一个网页添加为其被调试对象,然后使用新实例注册了一个新的 debugger; 语句处理程序。当您点击 div 元素时,它们都运行了。这展示了任意数量基于 Debugger 的工具如何可以同时观察单个网页——尽管它们的处理程序运行的顺序未指定,因此此类工具可能应该只观察,而不是影响被调试对象的行为。

  8. 关闭网页和 Scratchpad。

    由于 Scratchpad 的全局对象和被调试窗口现在都消失了,因此 Debugger 实例将被垃圾回收,因为它们不再对 Firefox 的行为有任何可见的影响。The Debugger API 试图尽可能透明地与垃圾回收交互;例如,如果 Debugger.Object 实例及其引用对象都不可访问,则它们都将被回收,即使属于该影子对象的 Debugger 实例继续存在。