Эффективное обнаружение изменений DOM в одностраничном приложении

#javascript #dom-events

#javascript #dom-события

Вопрос:

Я создаю библиотеку JS, и один из вариантов использования требует, чтобы я запускал событие при изменении DOM, особенно если это одностраничное приложение, например: панель поиска github После некоторых исследований, с которыми я столкнулся MutationObserver :

 // Dom change event listner
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
    attachListners();
    // ...
});

observer.observe(documentAlias, {
  subtree: true,
  childList: true
  //...
});
  

Проблема: библиотека, которую я создаю, предназначена для подключения к любому веб-сайту, поэтому я не могу контролировать реализацию html. Я немного обеспокоен тем, что использование наблюдателя мутаций может ввести бесконечный цикл. Видели много вопросов о переполнении стека в одной строке.

Есть ли какой-либо альтернативный / лучший подход? Как я могу безопасно и эффективно обнаруживать обновления / изменения DOM? Или лучше всего использовать mutation observer

Комментарии:

1. Наиболее эффективным подходом является вызов кода, который обновил dom, а не прослушивание изменений самостоятельно. Но, видимо, вы не можете / не хотите этого делать. Итак, какие обновления делает код, который вам нужно обнаружить? О каких изменениях dom мы говорим? Кто подключает библиотеку к своему веб-сайту и как?

2. @Bergi Это строка поиска, которая отображает результат точно так же, как пример github, который я показал выше. Если поиск обновляется при изменении запроса, мне нужно обнаружить эти новые обновленные результаты..

3. Я не знаю, что вы подразумеваете под «панелью поиска», или как это связано с линтером / форматером standardjs, который вы связали в качестве примера (?). Кто обновляет запрос или обновляет результаты и что ваш код делает с ними?

Ответ №1:

MutationObserver, вероятно, ваш лучший выбор. Раньше MutationObserver были события мутации, но теперь они устарели и не рекомендуются.

Другим (возможно, плохим) вариантом было бы использовать a setTimeout и периодически проверять DOM на наличие изменений. Но для этого вам потребуется написать функцию, чтобы получить узлы, которые вы хотите проверить, и сравнить текущее значение со старым значением. Это было бы не так эффективно, поскольку вы бы проверяли узлы каждые X миллисекунд, даже если изменений нет.

Вы должны быть в состоянии написать свой код таким образом, чтобы не возникал бесконечный цикл. Если вы получаете бесконечный цикл, вам следует добавить этот код в свой вопрос выше.

Что касается производительности, так MutationObserver как даст вам старые и новые значения, вы можете сравнить эти значения вместо обхода всего DOM. Например, что-то вроде этого:

 let observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    let oldValue = mutation.oldValue;
    let newValue = mutation.target.textContent;
    if (oldValue !== newValue) {
        // do something
    }
  });
});

observer.observe(document.body, {
  characterDataOldValue: true, 
  subtree: true, 
  childList: true, 
  characterData: true
});