Pull to refresh

Comments 18

Почему бы вам не использовать паттерн Наблюдатель вместо Посредника?
Каждый элемент может подписаться на событие, и каждый элемент может кидать событие — но нет Диспетчера. Имхо, это лишняя сущность в данном случае.
Это потому, что необходимо иметь несколько Диспетчеров.
Пример: кнопки оформления над textarea — они бросают одно и тоже событие «обрамитьТэгомВыделенныйТекст_вTextarea». На странице может быть несколько textarea (и несколько форм). Посредник позволяет направить событие в нужную textarea, а Наблюдатель потребует передачи ещё каких-нибудь параметров.

Если честно, я узнал про эти паттерны уже после реализации, когда писал статью (вот тут: www.artlebedev.ru/tools/technogrette/js/observable/ =)
Хм, лично на мой взгляд, Посредник в большинстве случаев совершенно лишняя штука — это лишний класс, который обладает знанием об окружающей системе, что усложняет замену конкретной реализации компонента системы на другую или добавление в систему/вычленение из системы еще одного компонента.

Смысл Наблюдателя в том и состоит, что компонент швыряет событие, а кто его поймает, и сколько подписчиков его поймает — совершенно его не интересует. К примеру, при клике на пункт меню швыряется событие «newsItemChosen», его подхватывает компонент Presentation и меняет оформление страницы, подхватывает компонент ContentHolder и меняет контент, подхватывает компонент Advertise и меняет рекламный блок. Пример, если что, высосан из пальца :)

А вот в приведенном тобой примере, когда надо указать конкретного получателя, но одновременно уменьшить связанность между компонентами системы, конечно, Посредник более правильное решение.
Как я понимаю, у меня не Посредник и не Наблюдатель, а Наблюдатель — это тот же посредник, только никто не знает про диспетчера (а он есть (с) =)

Мои Диспетчеры хоть и знают о существовании зарегистрированных у них компонент, но от разработчика это скрыто: есть только функции «зарегистрироваться» и «разрегистрироваться».

С другой стороны — иногда (ну очень редко) действительно нужно вводить лишний бесполезный класс Диспетчера только для диспетчеризации. Но гораздо чаще Диспетчер хранит какие-то данные, распределяет их по требованию или отправляет результат работы дочерних компонент куда-нибудь во вне. + К тому, у меня заложено, что если не указывать класс родительской компоненты, то событие побежит через дефолтный диспетчер — а фактически это и есть Наблюдатель.

> что усложняет замену конкретной реализации компонента системы
Системе пока 3 месяца, пока никого не напрягает, всё работает… но с другой стороны до замены чего-нибудь на другое пока не дошло… Посмотрим что будет. Хотя с третьей стороны — если что-то поменяется, то поменяется и HTML и CSS — а значит, что вероятность замены функционала всё равно очень велика…
такие вот «неявные связи» весьма сложны для понимания сторонним разработчиком. ибо каждый компонент сам по себе, а связи между ними появляются магическим образом. это всё-равно, что разработка без менеджера, где каждый программист разрабатывает что-то своё, а что получится в результате — никто не знает.

излишняя связность — это, конечно, плохо, но только излишняя. компоненте «текстария» безусловно не надо знать о компоненте «кнопа тулбара». и наоборот. а вот компонент «редактор» должен знать об обоих и координировать их взаимодействие. именно координировать, а не выступать курьером пересылающим сообщения от одного компонента другому.
> сложны для понимания сторонним разработчиком
что верно, то верно — вместе с JS придётся передавать и CSS и HTML (иначе ничего работать не будет =(

А что касается второго абзаца: я бы заменил слово «должен знать» на «может знать» — ведь, это просто другой алгоритм реализации того же самого и всё.
в общем случае такая схема не работает, ибо вёрстка бывает весьма разная, так что слушать события из другого конца страницы — вполне нормальная ситуация.

далее — компоненты по отдельности интерес как правило не представляют. интерес представляют виджеты — законченные миниприложения.

ну и, наконец, эффект «дрожания интерфейса»…

бывают 4 ситуации:
1. яваскрипт отключён — нужно показать интерфейс работающий без яваскрипта.
2. яваскрипт включён, но ещё не проинициализировался — нужно показать «приглушённый» яваскриптовый интерфейс.
3. яваскрипт включён, но не сработал — нужно показать безскриптовый интерфейс.
4. всё пучком — нормальный яваскриптовый интервейс.

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

проиллюстрирую на примере: ссылка на некоторую информацию, которая при наличии яваскрипта превращается в контрол открывающий аяксовый попап. пользователь привык к удобному и быстрому попапу, не уводящему его со страницы. но вот он открывает новую страницу и жмёт контрол, который ещё не проинициализировался. и попадает на другую страницу. «что за херня!» — думает он. и действительно, что за херня?
> не работает, ибо вёрстка бывает весьма разная
В этом случае события будут бегать через body, либо верстальщик будет аннигилирован.
Я всё же считаю, что это не нормально: вёрстка должна быть правильной, оформление — функциональным, а работа команды — эффективной. Так должно быть. Или вы считаете, что в общем случае Web-разработчики верстают «не правильно»?

> и действительно, что за херня?
Это гораздо лучше, чем ситуация в которой контент начинает показываться только после загрузки десятка JS файлов с общим весом килобайт в 200, потом после загрузки страницы должны загрузится ещё десять js-файлов.
Если страницу правильно соптимизировать, то недостатки, которые вы указали, совершенно не заметны + к тому описанную вами ситуацию с контролом можно избежать.
нет, всё правильно они верстают, просто ситуации бывают разные и логически связанные блоки не всегда идут подряд.
например: слева — несколько текстарий, а справа — панель инструментов, работающая с текущей текстарией.

не надо утрировать. 2-3 скрипта по 20кб сидящих в кэше достаточно для комфортного сёрфинга по сайту. кстати о кэше — у вас компоненты будут грузиться заново при переходе между страницами, ибо конфигурация компонент на каждой странице своя. вы решили проблему загрузки десятков файлов, но ценой лишнего потребления трафика и как следствие — дополнительного лага между появлением страницы и активацией компонент.

давай рассказывай, как соптимизировать и как избежать, я весь во внимании =)

кстати, ссылка по теме: jsx.ru — тот же подход, только без объединения файлов.
> слева — несколько текстарий, а справа — панель инструментов, работающая с текущей текстарией.
А, ну это да. Я видимо, не привык к таким интерфейсам )

> 2-3 скрипта по 20кб сидящих в кэше достаточно для комфортного сёрфинга по сайту
По статистике завтра-послезавтра этих скриптов всё равно уже не будет в кэше (Yahoo не даст соврать — я только ссылку на исследование потерял =( Так что кэш — не аргумент.

> дополнительного лага между появлением страницы и активацией компонент
Про лаг согласен, но только от части: этого лага заметно не будет! человек быстро получит страницу, сразу же начнёт интересоваться и читать сайт, а к тому времени как он опомнится — все компоненты будут инициализированны.

Про это и про «как соптимизировать» я целый талмуд написал: habrahabr.ru/blogs/client_side_optimization/38299/

> как избежать
Если очень хочется, чтобы непроинициализированный контрол выглядел не так как проинициализиварованный, можно загружать JS и CSS в одном файле. Вот пример: beatle.joos.nnov.ru/jas/Beatle, cHabr, List, Holder.js/ — это компонента-«корневой DIV списка из текста статьи».

> jsx.ru
Это, на самом деле, оригинал идеи (я ссылку на него ставил в пред.статье). У меня другая реализация + оптимизация Client-Side
Кстати, без объединения файлов там загружается аж 17 js-файлов. У меня — 3.
не особо важно, что будет завтра-послезатра. посещая подряд десять разных страниц, я буду десять раз грузить одни и те же скрипты.

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

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

при прямой загрузке скриптов скорость их загрузки равна [пинг]+[объём скриптов]*[количество скриптов]*[потоковую скорость]
при ленивой загрузке, на основе зависимостей — ([пинг]+[объём партии]*[потоковую скорость])*[количество партий] = [пинг]*[количество партий]+[объём партии]*[потоковую скорость]*[количество партий]
то есть, на загрузку по ленивой схеме тратится на [пинг]*[количество партий] больше.
при этом первая схема сразу оседает в кэше и работает сразу при отображении страницы, а вторая — зачастую (во всяком случае первое время) грузит каждый раз заново и изначально неработает.
вариант jsx — ещё более печальный, да.

объединять js и css — это, конечно, изврат :-) на мой взгляд достаточно просто загрузить стили со всем отображением, а скриптом уже переключать класс у элемента.
> не особо важно, что будет завтра-послезатра
>… я буду десять раз грузить одни и те же скрипты.
>… микрооптимизация… гроша выеденого не стоит
Ладно! =)

Рассмотрим пользователя, который в самый первый раз зайдёт на страницу.
Этот пользователь, по-любому, идёт на страницу не за контролами, ни в какое в избранное он добавлять ничего не будет, не будет нажимать на регистрацию, не будет комментировать. Не будет до тех пор, пока не поймёт: стоящая ли страница и весь остальной сайт или нет. Это всё потому, что он идёт на сайт за информацией. Если информация — текст, то он его получит быстро и начнёт читать и соображать. Если информация картинка или видео — то он дождётся загрузки. В это время всё загрузится и контролы будут работать.

Если человек вдруг сделает второй клик, то на следующей странице он должен будет загрузить: (1) html, (2) сгенерённые картинки-превьюшки, (3) баннеры, (4) 3-4 js-файла с компонентами, если страница не будет аналогичной первой (остальное — в кэше). Вторая страница покажется пользователю ещё более быстрой, он будет рад и счастлив. В этом случае задержка в работе контролов на долю секунды будет платой за счастье пользователя.

Рассмотрим постоянного пользователя с кэшем.
У этого чела есть все файлы в кэше. Для каждой новой страницы ему нужно будет догрузить только (1) html, (2) баннеры. Этот чел счастлив от того, что остался на сайте =)

Рассмотрим постоянного пользователя без кэша.
Да, этот пользователь может резко нажать мышкой на «добавить в избранное» в середине страницы. Но этот человек — явно либо псих, либо проверяет реализацию догрузки JS-файлов для компонент. Такие люди явно не считаются (хотя я тут могу ошибаться =) Я всё же думаю, что таких людей — единицы из тысячи — можно пренебречь (тут тоже возможна ошибка)

По поводу «хаотичной функциональности»: я не вижу тут никакой проблемы (я не вруЪ). Это вполне решаемая задача! В представленном мной примере эта задача не решалась (не было такой цели).

По поводу расчётов про «пинг», «объём», «всё такое»: судя по всему расчёт вёлся от момента начала загрузки страницы до надписи «Готово» в левом нижнем углу браузера. Я же твёрдо убеждён в том, что нужно делить этот промежуток времени на два: от начала до отображения контента и от отображения контента до «готово». Фактически у нас разные критерии правильности и разные формулы. Т.е. наши оценки скорости нельзя сравнивать: кто-то из нас неправ и третьего не дано =)

Про ленивую загрузку: вот ссылка dojotoolkit.org/demos/fisheye-demo
Это очень здорово работает, когда я первый раз это увидел, я был поражён возможностями dojo. Но по скорости загрузки — это Жесть, а не страница =)

> объединять js и css — это, конечно, изврат
Тут я почти согласен. У меня это всё автоматом собирается из тучи мелких файлов. Это не напрягает разработчика, делает быстрее загрузку, радует пользователя. Все счастливы, вобщем. А загружать все стили сразу — тоже вроде как нехорошо: не на всех страницах оно может потребоваться…
если информация — картинка, то сначала будет загружена она, а потом только скрипты. ибо основная концепция ненавязчивого яваскрипта — сначала появляется контент, а только потом подгружаются скрипты. если грузить скрипты между загрузкой страницы и загрузкой картинки, то это уже будет полумера: с одной стороны яваскрипт навязчив, с другой — лишняя задержка его загрузки.

плохо, что эта задача не решалась. конечно, куда интересней сначала придумать решение, а потом подобрать задачу, которую оно решает. при создании же хорошего продукта приходится решать комплекс задач, одной из которого является «обеспечение удобного и предсказуемого интерфейса». задача же обеспечения работоспособности в исключительных ситуациях (нет поддержки яваскрипта, скрипты не смогли загрузиться, скрипты не смогли проинициализироваться) обычно является менее приоритетной.

как я вижу правильное решение:

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

если скриптов много — сначала грузим загрузчик, который трансформирует контролы из пассивных в активные (использующие и неиспользующие скрипты) и вешает на их нажатие уведомление, что загрузка всё ещё продолжается и запоминает пользовательские действия, чтобы применить их сразу по загрузки скриптов. после этого начинает показываться страница и параллельно подгружаются скрипты. если загрузка обломалась (тока не по таймауту это надо проверять), или при инициализации скриптов вылезла ошибка — трансформируем активные контролы обратно в пассивные и по возможности применяем запомненные пользовательские действия.
причём, грузить скрипты лучше пакетами вида: «общие для сайта», «специфичные для раздела», «специфичные для страницы», — по мере необходимости, чтобы держать размеры файлов-скриптов в разумных пределах.

по поводу рыбьего глаза — это классический вариант плохого интерфейса. с ним интересно играть, но не удобно пользоваться. и чего тут в доджо такого особенного? рыбий глаз реализовали уже, наверно, на всех фреймворках…
Основная концепция «ненавязчивости» — не в порядке загрузки, а в необязательности JS. Следуя этому принципу разработчик должен обойти все подводные камни в виде «непредсказуемого интерфейса» — это решаемо.

Вы исходите из того, что «сначала загружается картинка, а потом — JS». Это не так.
Сначала загружается HTML, а потом всё остальное. При чём тяжёлая картинка и скрипты могут и должны загружаться параллельно (и скорее всего скрипты загрузятся быстрее).

(а рыбийглаз я увидел когда я знал только document.write и onclick='...' — тогда это было огого)
Эхх написать бы оптимизатор кода (хотя бы для себя). А вообще идея неплохая собрать в кучку оптимальные методы и в похожих случаях предлагать программеру воспользоваться одним из приёмчиков. Только как распознать что программер хочет выполнить именно эту задачу? Истина где то рядом…
ещё пара замечаний:

на страницу с большим числом модулей скрипты могут не прогрузиться из-за ограничения на длину урла.

вы вводите кастомные аттрибуты. это очень скользкий путь. в моей практике, например, был такой случай: на одном сайте был прикручен валидатор форм, который использовал безобидный аттрибут «pattern», которого не было в html4, но который появился в html5. вследствие этого в девятой опере формы вообще не сабмитились. лучше заведите себе отдельный неймспейс. ну, либо через onclick передавать параметры, как в jsx, хотя это и не слишком опрятное решение…
> скрипты могут не прогрузиться из-за ограничения на длину урла
В этом случае скриптов будет несколько. Например, вот тут: covex.in.nnov.ru/technology/799495.html

С нэймспейсами не всё так гладко — страницы могут быть не совсем валидным XML, третий FF стал как-то по другому работать с ними… А вообще +1. Надо покопать в эту сторону.
Sign up to leave a comment.

Articles

Change theme settings