Javascript Firefox Inspector';沃克在干什么?

Javascript Firefox Inspector';沃克在干什么?,javascript,firefox,firefox-addon,promise,firefox-developer-tools,Javascript,Firefox,Firefox Addon,Promise,Firefox Developer Tools,在Firefox中,在modules/devtools/inspector/inspector-panel.js的开头,您会看到一些对“walker”的引用,如本文末尾所示: ... /** * Represents an open instance of the Inspector for a tab. * The inspector controls the highlighter, the breadcrumbs, * the markup view, and the sideb

在Firefox中,在modules/devtools/inspector/inspector-panel.js的开头,您会看到一些对“walker”的引用,如本文末尾所示:

 ...

/**
 * Represents an open instance of the Inspector for a tab.
 * The inspector controls the highlighter, the breadcrumbs,
 * the markup view, and the sidebar (computed view, rule view
 * and layout view).
 *
 * Events:
 * - ready
 *      Fired when the inspector panel is opened for the first time and ready to
 *      use
 * - new-root
 *      Fired after a new root (navigation to a new page) event was fired by
 *      the walker, and taken into account by the inspector (after the markup
 *      view has been reloaded)
 * - markuploaded
 *      Fired when the markup-view frame has loaded
 * - layout-change
 *      Fired when the layout of the inspector changes
 * - breadcrumbs-updated
 *      Fired when the breadcrumb widget updates to a new node
 * - layoutview-updated
 *      Fired when the layoutview (box model) updates to a new node
 * - markupmutation
 *      Fired after markup mutations have been processed by the markup-view
 * - computed-view-refreshed
 *      Fired when the computed rules view updates to a new node
 * - computed-view-property-expanded
 *      Fired when a property is expanded in the computed rules view
 * - computed-view-property-collapsed
 *      Fired when a property is collapsed in the computed rules view
 * - rule-view-refreshed
 *      Fired when the rule view updates to a new node
 */
function InspectorPanel(iframeWindow, toolbox) {
  this._toolbox = toolbox;
  this._target = toolbox._target;
  this.panelDoc = iframeWindow.document;
  this.panelWin = iframeWindow;
  this.panelWin.inspector = this;
  this._inspector = null;

  this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
  this._target.on("will-navigate", this._onBeforeNavigate);

  EventEmitter.decorate(this);
}

exports.InspectorPanel = InspectorPanel;

InspectorPanel.prototype = {
  /**
   * open is effectively an asynchronous constructor
   */
  open: function InspectorPanel_open() {
    return this.target.makeRemote().then(() => {
      return this._getWalker();
    }).then(() => {
      return this._getDefaultNodeForSelection();
    }).then(defaultSelection => {
      return this._deferredOpen(defaultSelection);
    }).then(null, console.error);
  },

  get inspector() {
    if (!this._target.form) {
      throw new Error("Target.inspector requires an initialized remote actor.");
    }
    if (!this._inspector) {
      this._inspector = InspectorFront(this._target.client, this._target.form);
    }
    return this._inspector;
  },

  _deferredOpen: function(defaultSelection) {
    let deferred = promise.defer();

    this.outerHTMLEditable = this._target.client.traits.editOuterHTML;

    this.onNewRoot = this.onNewRoot.bind(this);
    this.walker.on("new-root", this.onNewRoot);

    this.nodemenu = this.panelDoc.getElementById("inspector-node-popup");
    this.lastNodemenuItem = this.nodemenu.lastChild;
    this._setupNodeMenu = this._setupNodeMenu.bind(this);
    this._resetNodeMenu = this._resetNodeMenu.bind(this);
    this.nodemenu.addEventListener("popupshowing", this._setupNodeMenu, true);
    this.nodemenu.addEventListener("popuphiding", this._resetNodeMenu, true);

    // Create an empty selection
    this._selection = new Selection(this.walker);
    this.onNewSelection = this.onNewSelection.bind(this);
    this.selection.on("new-node-front", this.onNewSelection);
    this.onBeforeNewSelection = this.onBeforeNewSelection.bind(this);
    this.selection.on("before-new-node-front", this.onBeforeNewSelection);
    this.onDetached = this.onDetached.bind(this);
    this.selection.on("detached-front", this.onDetached);

    this.breadcrumbs = new HTMLBreadcrumbs(this);

    if (this.target.isLocalTab) {
      this.browser = this.target.tab.linkedBrowser;
      this.scheduleLayoutChange = this.scheduleLayoutChange.bind(this);
      this.browser.addEventListener("resize", this.scheduleLayoutChange, true);

      // Show a warning when the debugger is paused.
      // We show the warning only when the inspector
      // is selected.
      this.updateDebuggerPausedWarning = function() {
        let notificationBox = this._toolbox.getNotificationBox();
        let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
        if (!notification && this._toolbox.currentToolId == "inspector" &&
            this.target.isThreadPaused) {
          let message = this.strings.GetStringFromName("debuggerPausedWarning.message");
          notificationBox.appendNotification(message,
            "inspector-script-paused", "", notificationBox.PRIORITY_WARNING_HIGH);
        }

        if (notification && this._toolbox.currentToolId != "inspector") {
          notificationBox.removeNotification(notification);
        }

        if (notification && !this.target.isThreadPaused) {
          notificationBox.removeNotification(notification);
        }

      }.bind(this);
      this.target.on("thread-paused", this.updateDebuggerPausedWarning);
      this.target.on("thread-resumed", this.updateDebuggerPausedWarning);
      this._toolbox.on("select", this.updateDebuggerPausedWarning);
      this.updateDebuggerPausedWarning();
    }

    this.highlighter = new Highlighter(this.target, this, this._toolbox);
    let button = this.panelDoc.getElementById("inspector-inspect-toolbutton");
    this.onLockStateChanged = function() {
      if (this.highlighter.locked) {
        button.removeAttribute("checked");
        this._toolbox.raise();
      } else {
        button.setAttribute("checked", "true");
      }
    }.bind(this);
    this.highlighter.on("locked", this.onLockStateChanged);
    this.highlighter.on("unlocked", this.onLockStateChanged);

    this._initMarkup();
    this.isReady = false;

    this.once("markuploaded", function() {
      this.isReady = true;

      // All the components are initialized. Let's select a node.
      this._selection.setNodeFront(defaultSelection);

      this.markup.expandNode(this.selection.nodeFront);

      this.emit("ready");
      deferred.resolve(this);
    }.bind(this));

    this.setupSearchBox();
    this.setupSidebar();

    return deferred.promise;
  },

  _onBeforeNavigate: function() {
    this._defaultNode = null;
    this.selection.setNodeFront(null);
    this._destroyMarkup();
    this.isDirty = false;
  },

  _getWalker: function() {
    return this.inspector.getWalker().then(walker => {
      this.walker = walker;
      return this.inspector.getPageStyle();
    }).then(pageStyle => {
      this.pageStyle = pageStyle;
    });
  },

  ...
我在中的任何地方都没有看到这个承诺的文档,是否有关于它是什么以及如何使用的文档(甚至源代码注释)

它是否可以用于在Firefox DevTools Inspector的DOM树视图中添加特殊样式或向某些元素添加一些图标?

每当在DevTools代码中提到“walker”时,它通常指toolkit/DevTools/server/actors/Inspector.js中的WalkerActor

Actor是javascript类,专门用于从当前检查的页面和上下文获取信息或对其进行操作

作为用户看到的工具的UI部分不会直接这样做。事实上,devtools使用客户机-服务器协议在工具箱(托管您使用的所有面板)和作为被检查页面的一部分运行的参与者之间进行通信。这就是允许使用这些工具检查远程设备的原因

特别是WalkerActor,它的作用是遍历DOM树,并向inspector面板提供有关节点的信息,以便在工具中显示

当您在页面上打开devtools检查器时,您看到的是DOM树的一部分(这一部分只是因为它没有完全展开,折叠的节点还没有被检索到),WalkerActor已经检索到它并(通过协议)发送到检查器面板

面板的实际UI呈现在浏览器/devtools/markupview/markup-view.js中的客户端(即工具箱端,与参与者/页面端相比)上完成

在此文件中,MarkupView和MarkupContainer类尤其负责显示节点。它们不是Addons API的特定部分,但应该相对容易获得它们,因为特权代码可以访问
gDevTools
全局变量:

Cu.import("resource://gre/modules/devtools/Loader.jsm");
let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
let inspectorPanel = toolbox.getPanel("inspector");
inspector.markup // Returns the instance of MarkupView that is currently loaded in the inspector

@paa谢谢,但我读到了Promise,这很有道理,但我仍然不知道Walker Promise到底做了什么,对于远程目标来说非常方便。哇,酷,有没有“FireShark”或插件,可以告诉这个协议中发送什么/发送什么和接收什么?我不知道,但是如果你从命令行启动Firefox(即在Mac上)然后在about:config中启用pref
devtools.debugger.log
,您将看到所有json数据包都通过网络发送和接收。