Pull to refresh

Comments 26

Я как-то не очень согласен с названием статьи, т.к. с каких пор подводными камнями фреймворка считается глупость и невнимательность лиц, использующих его

п1. Ты сам забыл импортировать то, что собираешься использовать (https://angular.io/api/core/NgModule#imports)

п2. Ты запрашиваешь из вьюхи элемент, которого нет на странице (https://angular.io/api/core/ViewChild#example-3)

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

п4. Выдавать за проблемы то, что вообще вроде-бы как и не проблема

п5. Ты сам на каждый вызов функции делаешь 100500 раз одинаковые вычисления, не почитав, как работает change detection

facepalm.jpg

Вот не надо кривой переусложнённый дизайн фреймворка прикрывать "глупостью" пользователей. Вот, смотрите, как те же проблемы выглядят, например, в $mol:


1) Пользовательская директива, которую вы применили, не работает

В $mol нет директив. Есть только композиция компонент. Соответственно "забыть" директиву невозможно. А даже если бы директивы и были, то забыть импортировать их тоже было бы невозможно, так как вручную в $mol ничего не импортируется. Написал директиву — её код включился в бандл автоматически, благодаря MAM. Не написал — не включился. Всё просто, надёжно и не требует от разработчика помнить об этой рутине.


2) ViewChild возвращает undefined

Так как все вложенные элементы в $mol компонентах объявляются как ленивые фабрики типа:


@ $mol_mem
Input() {
    return $mol_string.make({
        // overrides
    })
}

То получить экземпляр элемента можно в любой момент, даже если приложение ещё не запущено или инпут не рендерится:


this.Input() // компонент инпута
this.Input().dom_node() // дом-элемент инпута

3) Выполнение кода при обновлении списка, сгенерированного с помощью *ngFor

В $mol благодаря ОРП зависимости трекаются автоматически, так что никакая ручная синхронизация состояний не требуется.


4) Проблемы с ActivatedRoute.queryParam, возникающие в том случае, когда запросы можно выполнять без параметров

В $mol все зависимые состояния объявляются как инварианты от своих зависимостей. Система реактивности же гарантирует, что вычисленное значение будет ровно одно и ровно в ожидаемом виде. Выглядит это примерно так:


token() {
    return this.$.$mol_state_arg.value( 'accessToken' )
}

Опять программисту не нужно шаманить для получения единообразного поведения.


5) Медленная работа страниц

В $mol ререндер одного элемента не приводит к ререндеру другого. Ререндер любого элемента происходит лишь при изменении зависимостей, от непосредственно которых зависит состояние данного конкретного элемента. Аналогичный пример на $mol не вызвал бы никаких проблем с производительностью.


image

Написал директиву — её код включился в бандл автоматически

Что происходит, когда есть несколько директив с одним именем?


То получить экземпляр элемента можно в любой момент, даже если приложение ещё не запущено или инпут не рендерится:

Но никакие действия с элементом при этом совершить нельзя, толку-то тогда, от того, что элемент получили? Наоборот, это ведет к трудноотлаживаемым ошибкам.


В $mol благодаря ОРП зависимости трекаются автоматически, так что никакая ручная синхронизация состояний не требуется.

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


В $mol все зависимые состояния объявляются как инварианты от своих зависимостей. Система реактивности же гарантирует, что вычисленное значение будет ровно одно и ровно в ожидаемом виде.

Вы даже не поняли, в чем проблема. queryParams — это observable, так что он точно так же реактивно эмитит значения.


В $mol ререндер одного элемента не приводит к ререндеру другого.

Представьте себе — в ангуляре тоже. В приведенном примере нет никаких проблем с ререндером. На самом деле, можно вообще в mousemove заменить значения на константы и рендериться в принципе ничгео не будет. А тормозить — будет.

Что происходит, когда есть несколько директив с одним именем?

Вы это просто не сможете сделать, так как все имена глобально уникальны.


Но никакие действия с элементом при этом совершить нельзя, толку-то тогда, от того, что элемент получили? Наоборот, это ведет к трудноотлаживаемым ошибкам.

Можете совершать с ним любые действия.
О какого рода ошибках идёт речь?


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

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


Вы даже не поняли, в чем проблема. queryParams — это observable, так что он точно так же реактивно эмитит значения.

А вы даже не поняли, что в $mol нет ни обсерваблов, ни эмитов значеий, ни этой проблемы.


Представьте себе — в ангуляре тоже. В приведенном примере нет никаких проблем с ререндером.

А давайте не спорить о терминах?


На самом деле, можно вообще в mousemove заменить значения на константы и рендериться в принципе ничгео не будет. А тормозить — будет.

А в $mol тормозить не будет.

Вы это просто не сможете сделать, так как все имена глобально уникальны.

В смысле не могу? Могу. Вот просто взял и объявил две директивы с одним именем. Что произойдет, как ваш фреймворк реагирует на такую ситуацию?


Можете совершать с ним любые действия.

Какие любые действия я могу с ним совершать, если элемента нет? С чем я буду их совершать?


О какого рода ошибках идёт речь?

Строка кода выполнена, но действие над элементом не совершено, т.к. элемента еще в тот момент не было.


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

Нет, это она как раз отследить могла. Она не могла отследить, что список перерендерился.


А вы даже не поняли, что в $mol нет ни обсерваблов, ни эмитов значеий, ни этой проблемы.

Как вы можете утверждать что такой проблемы нет, если вы не поняли, в чем вообще была проблема?


А давайте не спорить о терминах?

Речь не о терминах а о смысле.


А в $mol тормозить не будет.

Будет что-то другое.

UFO just landed and posted this here
А если нужно написать юнит-тесты и сделать заглушку (нейтрализовать роботу директивы)?

  1. Лучше писать компонентные тесты, а не модульные.
  2. Если без мока никак — просто просто переопределяете класс "директивы" в тестовом контексте.

А если импортировать внешний модуль, где есть точно такое же название директивы, падает ошибка?

У вас это не получится, так как имя модуля должно соответствовать его расположению, иначе он банально не будет найден. Даже если вам удастся создать два одноимённых класса, то будет ошибка компиляции.

В смысле не могу? Могу. Вот просто взял и объявил две директивы с одним именем. Что произойдет, как ваш фреймворк реагирует на такую ситуацию?

Тайпскрипт упадёт с ошибкой.


Какие любые действия я могу с ним совершать, если элемента нет? С чем я буду их совершать?

Он создаётся в момент обращения.


Строка кода выполнена, но действие над элементом не совершено, т.к. элемента еще в тот момент не было.

Боюсь это не возможно.


Будет что-то другое.

И что же?

Тайпскрипт упадёт с ошибкой.

  1. А если тайпскрипта нет?
  2. Даже если тайпскрипт — он с ошибкой в таких случаях не падает
  3. А если бы падал — это кто-то в какой-то зависимости зависимости объявил директиву и теперь мне в своем проекте надо свою переименовывать, т.к. иначе — "падает"? Очень удобно.

Он создаётся в момент обращения.

Нет, не создает, т.к. в момент обращения еще неизвестно, что там за объект.


Боюсь это не возможно.

Ну либо ошибка либо действие не выполнено. Других вариантов нет.


И что же?

Это вы мне скажите.

А если тайпскрипта нет?

В $mol его не может не быть.


Даже если тайпскрипт — он с ошибкой в таких случаях не падает

При объявлении одноимённых классов? Ещё как падает.


А если бы падал — это кто-то в какой-то зависимости зависимости объявил директиву и теперь мне в своем проекте надо свою переименовывать, т.к. иначе — "падает"? Очень удобно.

Свои сущности именуются в своём неймспейсе.


Нет, не создает, т.к. в момент обращения еще неизвестно, что там за объект.

Известно.


Ну либо ошибка либо действие не выполнено. Других вариантов нет.

О какого рода действиях идёт речь?


Это вы мне скажите.

Как только найду — я вам сообщу.

При объявлении одноимённых классов? Ещё как падает.

В разных модулях? Не падает.


Известно.

Откуда? Не известно ничего. Какая дом-нода там будет, может зависеть, например, от фазы луны (в смысле натурально от фазы луны, без преувеличений).


О какого рода действиях идёт речь?

Действиях с дом-нодой, которой нет.


Как только найду — я вам сообщу.

То есть, вы не знаете граничных кейсов, на которых ваш фреймворк дает плохую производительность? Печально.

В разных модулях? Не падает.

В $mol не используются js-modules. Там весь код объявляется примерно так:


namespace $ {
    export class $my_component {}
}

Откуда?

Благодаря pull семантике с мемоизацией. Я же писал в самом начале как объявляются свойства: https://habr.com/ru/company/ruvds/blog/459304/#comment_20382138
Дом-элемент точно так же создаётся при первом обращении и запоминается.


То есть, вы не знаете граничных кейсов, на которых ваш фреймворк дает плохую производительность?

А что такое "плохая производительность"?

Благодаря pull семантике с мемоизацией.

Но информации об объекте-то нет. Ее в принципе нет и быть не может, т.к. до непосредственно исполнение неизвестно, в какой фазе луны запущен скрипт.


Дом-элемент точно так же создаётся при первом обращении и запоминается.

Какой элемент? Мы же до того, как элемент будет создан, этого не знаем и узнать не можем.

О каких ещё фазах луны идёт речь? Тут всё предельно детерминировано.


Элемент создаётся в момент обращения к нему. Даже не знаю, как это объяснить ещёпонятней.

О каких ещё фазах луны идёт речь?

Об обычных. В зависимости от фазы там будет либо элемент Х либо элемент Y либо вообще не будет никакого элемента.
Какой именно элемент вы тогда собираетесь "детерменировано" создавать во время "обращения"?

Вы какие-то странные вещи говорите. Не может там быть разных элементов. Архитектура такая.

Вы какие-то странные вещи говорите. Не может там быть разных элементов.

В смысле? В вашем фреймворке нельзя ни выводить дом-ноду по условию, ни сгенерировать эту ноду динамически? Уверен, что можно, иначе фреймворк был бы бесполезен. А значит, там может быть любой элемент.

Можно. Но логика описывается в виде инвариантов и не может просто так сломаться.

Можно.

Отлично! Так какой элемент там будет, когда его еще нет и даже неизвестно, каким он должен быть?

Какой вернёте из функции — такой будет.


@ $mol_mem
canvas() {
    return document.createElement( 'canvas' )
}

@ $mol_mem
context() {
    return this.canvas().getContext( '2d' )
}

@ $mol_mem
context_with_rect() {
    const context = this.context()
    context.fillRect( 0 , 0 , 10 , 10 )
    return context
}
Какой вернёте из функции — такой будет.

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

Они точно так же создаются. У вашего компонента есть метод dom_node, который возвращает дом элемент. Есть реализация его в базовом классе. Можете переопределить его как угодно. Сам по себе фреймворк ничего не делает. Это не более чем набор библиотек.

Они точно так же создаются.

В какой момент, и что происходит, когда я пытаюсь обратиться к элементу, когда он еще не создан?

Он создаётся в момент обращения и кешируется.

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

В моле вообще нет шаблонов. А обратиться можно к чему угодно.

Sign up to leave a comment.