Here is a use case:
Assume we have a web page that has an issue, which results in the page to be scrolled up on a mobile device at some point after DOMContentLoaded has fired.
We can legitimately assume there is something, which operates on document.documentElement.scrollTop (e.g. assigns it a value of 0).
Suppose we also know there are hundreds of places, where this can happen.
To debug the issue we can think of the following strategies:
check each event handler, which can set a value of 0 scrollTop, one by one
try to use debug function available in Chrome DevTools
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);
The issue with the second approach is that it doesn't work with native getters/setters.
The issue with the third approach is that even though now we can easily track what is assigning a value to the scrollTop property, we monkey patch a native getters/setters and risk to cause unnecessary side effects.
Hence the question: is there a more elegant solution to debug native getters and setters for web browser host objects (e.g. document, window, location, etc)?
Turns out it is possible to use debug
function for set
method on a scrollTop
property descriptor.
The code is as follows:
debug(Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop').set);
After that, we'll automatically stop in any function that tries to set a value to scrollTop
.
If you need to automatically stop only on those functions which assign a value within a certain threshold (for example, between 0 and 500), you can easily do that too since debug
function accepts a second argument (condition) where you can specify your condition logic.
For example:
// 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');
Pros:
Cons:
Many thanks to Aleksey Kozyatinskiy (former Googler on DevTools team) for the detailed explanation.