← Назад к вопросам
В чем разница между Promise и MutationObserver?
2.7 Senior🔥 91 комментариев
#JavaScript Core#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между Promise и MutationObserver
Promise и MutationObserver - это два совершенно разных инструмента, работающих в разных слоях JavaScript и браузера. Они решают разные задачи и имеют разные места в Event Loop.
Promise - для асинхронных операций
Promise используется для обработки асинхронного кода:
// Пример 1: Загрузка данных с сервера
const fetchUser = (id: string): Promise<User> => {
return fetch(`/api/users/${id}`)
.then(res => res.json());
};
fetchUser('123')
.then(user => console.log('User loaded:', user))
.catch(error => console.error('Failed to load:', error));
// Пример 2: Ожидание в коде
async function processData() {
const data = await fetchData();
console.log('Got data:', data);
}
Promise жизненный цикл:
const myPromise = new Promise((resolve, reject) => {
// Pending state - выполняется сразу
console.log('Promise created');
setTimeout(() => {
resolve('Done!'); // -> Fulfilled state
// или reject('Error'); -> Rejected state
}, 1000);
});
myPromise
.then(result => console.log(result)) // 'Done!'
.catch(error => console.error(error));
MutationObserver - для наблюдения за DOM
MutationObserver следит за изменениями DOM:
// Пример 1: Следить за всеми изменениями элемента
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
console.log('DOM changed:', mutation.type);
// mutation.type может быть:
// - 'attributes' - изменился атрибут (class, id, style)
// - 'childList' - добавлен/удален дочерний элемент
// - 'characterData' - изменился текстовый контент
});
});
const element = document.getElementById('myElement');
observer.observe(element, {
attributes: true, // Следить за атрибутами
childList: true, // Следить за добавлением/удалением дочерних элементов
characterData: true, // Следить за изменением текста
subtree: true // Следить и за потомками
});
// Остановить наблюдение
observer.disconnect();
Пример 2: Практическое применение
// Следить за появлением элемента
const observer = new MutationObserver((mutations) => {
const newElement = document.querySelector('.dynamic-element');
if (newElement) {
console.log('New element appeared!');
// Выполнить действие
observer.disconnect(); // Перестать следить
}
});
observer.observe(document.body, { childList: true, subtree: true });
Ключевые отличия
1. Назначение
// Promise - обработка асинхронных операций
Promise:
- Загрузка данных
- Таймауты
- I/O операции (fetch, file reading)
- Любая асинхронность
// MutationObserver - наблюдение за DOM
MutationObserver:
- Следить за изменениями DOM
- Реагировать на добавление/удаление элементов
- Отслеживать изменения атрибутов
- Работать с динамически создаваемым контентом
2. Когда выполняются в Event Loop
console.log('1. Start');
Promise.resolve()
.then(() => console.log('2. Promise (microtask)'));
const observer = new MutationObserver(() => {
console.log('3. MutationObserver (microtask)');
});
const element = document.createElement('div');
observer.observe(element, { childList: true });
element.appendChild(document.createElement('span'));
console.log('4. End');
// Порядок вывода:
// 1. Start
// 4. End
// 2. Promise (microtask) <- Promise выполнится раньше
// 3. MutationObserver (microtask) <- MutationObserver выполнится после
// Почему? Обе - микротаски, но Promise имеет приоритет
3. Инициирование
// Promise - инициируется явно
const promise = new Promise((resolve) => {
resolve('value');
});
// MutationObserver - автоматически срабатывает при изменении DOM
const observer = new MutationObserver(callback);
observer.observe(element, { childList: true });
// callback сработает при ANY изменении childList
4. Количество вызовов
// Promise - выполняется один раз
const promise = new Promise((resolve) => {
resolve('value');
});
promise.then(() => console.log('Executed once'));
// Выведет ОДИН раз
// MutationObserver - может срабатывать много раз
const observer = new MutationObserver(() => {
console.log('DOM changed');
});
observer.observe(document.body, { childList: true });
document.body.appendChild(document.createElement('div')); // Срабатывает
document.body.appendChild(document.createElement('div')); // Срабатывает снова
document.body.appendChild(document.createElement('div')); // Срабатывает еще
// Будет вызвана 3 раза
Использование на практике
Пример 1: Ждать загрузку элемента (MutationObserver)
function waitForElement(selector: string): Promise<Element> {
return new Promise((resolve) => {
const element = document.querySelector(selector);
if (element) {
resolve(element);
return;
}
const observer = new MutationObserver(() => {
const element = document.querySelector(selector);
if (element) {
resolve(element);
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
// Использование
await waitForElement('.dynamic-element');
console.log('Element found!');
Пример 2: Следить за изменениями класса (MutationObserver)
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
const element = mutation.target as HTMLElement;
const classes = element.className;
console.log('Classes changed to:', classes);
}
});
});
const button = document.querySelector('button')!;
observer.observe(button, { attributes: true });
button.classList.add('active'); // Срабатывает MutationObserver
Пример 3: Комбинирование Promise и MutationObserver
function waitForDataLoad(): Promise<void> {
return new Promise((resolve) => {
const observer = new MutationObserver((mutations) => {
// Проверяем если данные загружены
const dataElement = document.querySelector('[data-loaded]');
if (dataElement) {
observer.disconnect();
resolve();
}
});
observer.observe(document.body, { childList: true, subtree: true });
});
}
// Использование
await waitForDataLoad();
console.log('Data is loaded!');
Когда использовать что
// ИСПОЛЬЗУЙ PROMISE когда:
✓ Нужно дождаться асинхронной операции (fetch, setTimeout)
✓ Нужно обработать результат операции
✓ Нужна цепочка асинхронных операций
✓ Нужна обработка ошибок
const data = await fetch('/api/data').then(r => r.json());
// ИСПОЛЬЗУЙ MutationObserver когда:
✓ Нужно реагировать на изменения DOM
✓ Нужно следить за динамически добавляемым контентом
✓ Нужно найти элемент, который может появиться позже
✓ Нужно отслеживать изменения атрибутов
const observer = new MutationObserver(() => {
console.log('DOM changed');
});
observer.observe(element, { attributes: true });
Важные моменты
// MutationObserver может быть heavy
// Каждое изменение вызывает callback
const observer = new MutationObserver(() => {
performHeavyComputation(); // Может замедлить приложение!
});
observer.observe(document.body, { childList: true, subtree: true });
// Лучше добавить debounce
import { debounce } from 'lodash';
const observer = new MutationObserver(
debounce(() => {
performHeavyComputation();
}, 300)
);
observer.observe(document.body, { childList: true, subtree: true });
Заключение
Promise - это инструмент для работы с асинхронностью, часть JavaScript. MutationObserver - это инструмент для наблюдения за DOM, браузерный API.
Они не конкурируют, а дополняют друг друга. Часто их используют вместе: Promise ждет результат, MutationObserver следит за изменениями DOM.