Comments 20
Чтобы можно было агрегировать обновления и вызывать обработчик один раз на несколько элементов. В статье пример есть
const ro = new ResizeObserver(entries => {
// вызовется один раз сразу для всех обозреваемых элементов
})
// мы можем следить за любым количеством элементов
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))
с событиями были бы отдельные коллбеки на каждый элемент
Т.е. вместо того, чтобы реализовать обычный медиатор — чуваки из гугла закостылили это дело под один единственный юз кейс.
Даже ничего едкого и сарказмообразного в адрес подобных предложений не хочется добавлять. Просто стдлиб JS ещё на шаг ближе к помойке, не первый раз уже.
Не знаю как отредактировать в моб. версии и дополнить, так что дополнение в виде коммента:
Помимо реализации медиатора есть более юзабельная фича под данную задачу и доступна с IE версий времён мамонтов, когда на любые атрибуты тегов (ака свойства DOM) можно подписываться.
Во-первых, не единственный, у нас уже есть MutationObserver, работающий точно так же.
Во-вторых, а как бы выглядел код с использованием "обычного медиатора"?
Во-вторых, а как бы выглядел код с использованием "обычного медиатора"?
Ну медиатор — это более общая реализация, позволяющая перейти к частной. Мб что-то вроде такого.
const bus = new Bus(document);
bus.addEventListener('resize', e => { ... });
Ну или в виде ещё более частной реализации:
const bus = new Bus(dom1, dom2);
bus.addEventListener('resize', e => { ... });
Смысл в единой шине событий для нужных элементов. А "синхронизацию событий" можно добавить дополнительным аргументом или реализацией интерфейса шины событий:
const bus = new SyncBus(...);
P.S. Т.е. все мои претензии сводятся к тому, что:
1) Закостылено под ресайз (нахрена?)
2) Нарушен дизайн языка (события всегда делались через addEventListener).
P.P.S. Но вообще, если так уж приспичило, то этот ResizeObserver реализуется, кажется, двумя тычками на нативном JS:
class ResizeObserver {
_events = [];
constructor(callback) {
this.callback = callback;
}
_fire(e) {
this._events.push(e);
if (this.events.length > 0) {
requestAnimationFrame(() => {
this.callback(this.events);
this.events = [];
});
}
}
observe(el) {
el.addEventListener('resize', this._fire);
}
}
Если что, то я не являюсь JS разработчиком, так что могу ошибаться =)))
1) Закостылено под ресайз (нахрена?)
ResizeObserver заточен под ресайз. Что тут не так?
2) Нарушен дизайн языка (события всегда делались через addEventListener).
MutationObserver существует со времен IE9, то есть уже лет 10 как.
ResizeObserver заточен под ресайз. Что тут не так?
Т.е. захламлять стдлиб тем, чем будут пользоваться избранные единицы — это нормально? Вместо более общего решения, которое и решит данную задачу и позволит реализовать другие.
Если ответ будет "да, т.к. это оптимизация, которая нужна", то как часто вы в css прописываете will-change? Ну или как часто каждый addEventListener синхронизируете через requestAnimationFrame? Насколько часто делите стили на пререндер (минимальное отображение и гереация сетки) и рантайм (те, которые стартуются из Vue/CssInJS/etc)?
Я хочу донести мысль, что обратно всё вернуть взад будет невозможно. Всё больше всяких "фич" для оптимизации, которыми особо никто не пользуется. И мне кажется, что за всю историю был только один случай подобных откатов — это тег marquee, который ныне не работает. Но могу ошибаться.
В любом случае — есть хороший доклад от Андрея Бреслава про дизайн языков с примерами, когда однажды введённые крутые и полезные возможности в Java в будущем просто мешали дорабатывать язык.
MutationObserver существует со времен IE9, то есть уже лет 10 как.
Если смотреть отдельно, то в IE было невероятно огромное количество уникального функционала для разработчиков, который потом переняли и другие. Но насколько сам браузер выполнял хорошо выполнял свою работу?
Ну или другой пример — Opera 12. До сих пор по юзабилити и плюшек для пользователей ему конкурентов особых-то и нет. Но как браузер насколько он качественно выполнял свою работу?
А вот в хромиуме (современная опера, хром и прочие) плюс ФФ работает ResizeObserver. Им уже можно пользоваться, пожалуйста. Вы считаете его действительно наиболее полезным, нежели добавление фичи а-ля Swift, когда на любую существующую переменную можно повесить обсверер, вроде такого:
let a = 23;
a.subscribe((oldValue, newValue) => ...);
Т.е. одна фича, которая и перекроет функционал этого MutationObserver (он не нужен будет) и решит все проблемы one\two-way биндингов всех существующих JS фреймворков, и кучу других "чего-то, что придумать можно"?
Но если добавят эту фичу (вдруг!), то что делать с функционалом, который теперь не нужен будет (например, упомянутый вами MutationObserver)? А им ведь кто-то пользуется… А ведь обратного пути нет. Лет через 10 разве что… Или 20...
Вот именно из-за этого мне и кажется такое решение очередным костылём, которое добавляет ещё больше проблем (в перспективе) и которое призвано закрывать какой-то очень редкий кейс и который можно и так реализовать кодом, похожим на приведённый мною пример выше.
Надеюсь я достаточно развёрнуто пояснил свою мысль? =)
Но как браузер насколько он качественно выполнял свою работу?
Вполне качественно, до тех пор, пока не устарел.
на любую существующую переменную можно повесить обсверер, вроде такого:
Не, погодите. Обсерверы для DOM и обсерверы для объектов JS — это совсем разное.
Не, погодите. Обсерверы для DOM и обсерверы для объектов JS — это совсем разное.
Только у нас DOM напрямую связан с их моделями. При изменении значений вьюхи меняются данные в JS модели, при изменнии модели — меняется вьюха.
let input = document.getElementById('input-el');
input.value.subscribe(...);
input.value = 'new text';
Ну, связан, замечательно.
Я имел в виду, что работа с объектами JS и дёрганье за DOM API — это разного уровня сложности задачи. Подписка на переменную и подписка на свойство DOMElement — под капотом будут по разному работать.
function cb() {...}
dom1.addEventListener('resize', cb);
dom2.addEventListener('resize', cb);
В чем разница?
Можно подумать, что ResizeObserver будет вызываться один раз, если поменяются два элемента. Они же не могут измениться в один и тот же момент времени.
Плюс, опять же, если вы слушаете два элемента, значит это зачем-то надо. Иначе бы следили только за одним.
Кроме разве что вложенных элементов, но я не знаю зачем их одновременно слушать понадобится.
Экономия на несуществующих спичках, которая при этом выворачивает наизнанку событийную модель JS. Не то что бы это плохо, но непривычно точно.
Несколько элементов в одном общем контейнере?
del
ResizeObserver — новый мощный инструмент для работы с адаптивностью