Pull to refresh

Comments 20

UFO just landed and posted this here

Чтобы можно было агрегировать обновления и вызывать обработчик один раз на несколько элементов. В статье пример есть


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 — под капотом будут по разному работать.

Ну если изменение свойств ДОМа меняет свойства JS (в частности bound rect для ресайза), то почему это должно иметь какое-то значение?

изменение своств DOM не меняет js. это геттеры
function cb() {...}
dom1.addEventListener('resize', cb);
dom2.addEventListener('resize', cb);


В чем разница?

Можно подумать, что ResizeObserver будет вызываться один раз, если поменяются два элемента. Они же не могут измениться в один и тот же момент времени.
Плюс, опять же, если вы слушаете два элемента, значит это зачем-то надо. Иначе бы следили только за одним.

Из документации на MDN


Implementations should, if they follow the specification, invoke resize events before paint and after layout.

То есть, если элементы поменялись за один проход, без лишних перерисовок, то вы получите один вызов на все подписанные элементы.

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

Экономия на несуществующих спичках, которая при этом выворачивает наизнанку событийную модель JS. Не то что бы это плохо, но непривычно точно.

Несколько элементов в одном общем контейнере?

Если они ресайзятся в один фрейм, значит они как-то привязаны по размерам к родителю. Слушайте родитель.

Я понимаю, что можно придумать такую ситуацию и может быть она даже окажется нужной. Но к событиям все привыкли, а тут придумали что-то новое ради чего-то нового.
Лучше бы добавили новое событие для элемента. При его наличии всю функциональность описанную в статье можно было реализовать на rxjs, например
Sign up to leave a comment.

Articles