0

这是一个用例:

假设我们有一个有问题的网页,这导致页面在DOMContentLoaded触发后的某个时间点在移动设备上向上滚动。

我们可以合理地假设有一些东西在document.documentElement.scrollTop上运行(例如,给它赋值0)。

假设我们也知道有数百个地方会发生这种情况。

要调试问题,我们可以考虑以下策略:

  • 检查每个事件处理程序,它可以设置一个值为 0 scrollTop,一个一个

  • 尝试使用Chrome DevTools 中提供的调试功能

  • 将本机 scrollTop 覆盖为:

var scrollTopOwner = document.documentElement.__proto__.__proto__.__proto__;
var oldDescr = Object.getOwnPropertyDescriptor(scrollTopOwner, 'scrollTop');
Object.defineProperty(scrollTopOwner, '_oldScrollTop_', oldDescr);
Object.defineProperty(scrollTopOwner, 'scrollTop', {
  get:function(){
    return this._oldScrollTop_;
  },
  set: function(v) {
    debugger;
    this._oldScrollTop_ = v;
  }
});

function someMethodCausingAPageToScrollUp() {
  document.scrollingElement.scrollTop = 1e3;
}

setTimeout(someMethodCausingAPageToScrollUp, 1000);

第二种方法的问题在于它不适用于本机 getter/setter。

第三种方法的问题是,即使现在我们可以轻松地跟踪为scrollTop属性分配值的内容,但我们会对原生 getter/setter 进行修补,并有可能导致不必要的副作用。

因此问题是:是否有更优雅的解决方案来调试 Web 浏览器主机对象(例如文档、窗口、位置等)的本机 getter 和 setter?

4

2 回答 2

0
const collector = [];
const originalScrollTop = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop');
Object.defineProperty(Element.prototype, 'scrollTop', {
    get: () => originalScrollTop.get.call(document.scrollingElement),
    set: function(v) {
        collector.push((new Error()).stack)
        originalScrollTop.set.call(document.scrollingElement, v)
    }
})

您可以收集堆栈跟踪并稍后检查它们。我们不会立即记录它,以免造成 IO 延迟。在 Chrome 中工作。

于 2018-12-20T11:19:05.050 回答
0

事实证明,可以在属性描述符上使用debug函数作为set方法。scrollTop

代码如下:

debug(Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop').set);

之后,我们将自动停止任何试图将值设置为的函数scrollTop。如果您只需要自动停止那些在某个阈值内(例如,在 0 到 500 之间)分配值的函数,您也可以轻松地做到这一点,因为debug函数接受第二个参数(条件),您可以在其中指定条件逻辑.

例如:

// In that case, we'll automatically stop only in those functions which assign scrollTop a value within a range of [1, 499] inclusively
debug(Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop').set, 'arguments[0] > 0 && arguments[0] < 500');

优点:

  • 易于使用,不需要大量样板代码

缺点:

  • 每次刷新页面时,您都必须评估上面的 js 片段

非常感谢Aleksey Kozyatinskiy(DevTools 团队的前 Google 员工)的详细解释。

于 2019-06-15T01:39:17.033 回答