Как отследить вызывающего абонента для собственных получателей / установщиков хост-объектов в браузере? - PullRequest
0 голосов
/ 30 ноября 2018

Вот пример использования:

Предположим, у нас есть проблема с веб-страницей, которая приводит к прокрутке страницы на мобильном устройстве в некоторый момент после DOMContentLoaded сработал.

Мы можем законно предположить, что есть что-то, что работает с document.documentElement.scrollTop (например, присваивает ему значение 0 ).

Предположим, мы также знаем, что существуют сотни мест, где это может произойти.

Для устранения проблемы мы можем подумать о следующих стратегиях:

  • проверить каждуюобработчик событий, который может установить значение 0 scrollTop , один за другим

  • попытаться использовать функцию debug , доступную в 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);

Проблема второго подхода заключается в том, что он не работает с собственными средствами получения / установки.

Проблема третьего подхода заключается в том, что, хотятеперь мы можем легко отследить, что присваивает значение свойству scrollTop , мы обезьяны исправляем нативные методы получения / установки и рискуем вызвать ненужные побочные эффекты.

Отсюда вопрос: есть либолее элегантное решение для отладки собственных методов получения и установки для узлов хоста веб-браузера (например, документа, окна, местоположения и т. д.)?

Ответы [ 2 ]

0 голосов
/ 15 июня 2019

Оказывается, можно использовать функцию 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 выше при каждом обновлении страницы

Большое спасибо Алексей Козятинский (бывший Googler наКоманда DevTools) за подробное объяснение.

0 голосов
/ 20 декабря 2018
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)
    }
})

Вы можете собирать следы стека и проверять их позже.Мы не регистрируем это немедленно, чтобы не вызвать задержки ввода-вывода.Работает в Chrome.

...