Pull to refresh

Comments 36

Ну да, всё логично и стройно.
Только я малость не догнал, зачем писать в onclick?
Вполне же можно свой аттрибут завести на крайний случай.
onclick дает из коробки всю выразительность JS. Как только вы начинаете передавать данные на вход одних строк становится мало, захочется отдать структуру. Если свой аттрибут, то однозначно строка которую потом захотите прогнать через eval. onclick это все инкапсулирует.
а если кроме onclick есть onkeypress? Опять туда писать то же самое?
не удобнее ли сделать обертку для работы с DOMElements который бы сделал получение служебных данных прозрачным?
Смысл в том что, нет навешиваний событий через аттрибуты. Поэтому атрибуты освободились и оказались кстати для прокидывания входных данных. Какой именно использовать без разницы.
Да, спасибо — теперь понял.
Интересное решение, но очень уж не нравится, что это вешается на onclick.
А так как JS-ядро обходит DOM дерево и данные о элементе стираются из результирующего DOMа, мне кажется, что проще его(ядро) обучить читать и eval'ить атрибут, чем удалять за собой костыли.

Другими словами, этот малюсенький profit в одном месте, нарушает семантику языка, лишает некоторых возможностей(например реинициализация объекта уже невозможна, т.к. данные из тегов уже удалены) и меня это сильно коробит.
Я рад что мои аргументы понятны, но в целом это не самая принципиальная часть доклада. Есть места намного интереснее.
Ну, для меня пожалуй этот один из самых интересных моментов. Остальные пришлось уже решать и мы пришли к тем же решениям :)

Можно 2 вопросика. Один по теме, а второй околотопиковый.
Как же вы все же теперь разделяете и именуете js-файлы. По какому принципу?

И вы «гадите» в window? т.е. позволяете ли себе такие конструкции:

function a() {...};
b = new a(); /* window.b */
Разделяем и именуем отталкиваясь от функционала, который файл реализует.

Про window, естественно кинуть в window один объект и все за него спрятать это правильно и мы к этому идем. Но на данный момент не могу этим похвастать очень много легаси кода и путь будет длинный.
Ну да, разве что для более красивой и удобной обертке атрибутов в JSON.
Но лично мне не попадалось ситуаций, где нужны были бы сложные структуры, максимум 2-3 дополнительных атрибута.
Тогда этот вопрос не принципиален. Просто я уже давно не делал проекты которым меньше 10 лет и которые еще поддерживать и поддерживать. В этих условиях лучше сразу заложиться на структуру.
согласен, я для таких целей использую в тегах атрибут data-type
data-type хороший вариант, но опять же это строки. Плюс не забываем про старые браузеры, для них нужно будет писать поддержку. Повторюсь, onclick не имеет этих недостатков.
> Плюс не забываем про старые браузеры, для них нужно будет писать поддержку
То есть? Как бы нарушается только корректность XHTML'a, в DOM'e атрибуты появятся даже без всяких танцев и не для 'data-*', а просто для 'my_type', скажем.
А корректность XHTML'a правится введением кастомных DTD.
Но я хз, зачем добавиться верификации всяких стандартов, когда мы имеем парк браузеров со своими «особенностями». ИМХО, пусть сначала браузеры придут к идентичной работе, тогда можно будет уже стандартизировать страницы.
Я не про валидность. Нужно писать код, который будет обрабатывать атрибуты. Вопрос, зачем если это код есть в браузере?
Не знаю, mis-use, есть такое слово.
Да можно, например, ходить за продуктами с туристическим рюкзаком. Удобно, практично (сколько в пакетах унесете? а в рюкзаке килограмм 50 — легко). Одни плюсы, но как-то странно всё это. Ведь не для этого же он разрабатывался :)
By design onclick() — интерфейсное событие, генерируемое браузером в ответ на действия юзера. Здесь же предлагается забыть о том что это событие, забыть о том когда событие генерируется, использовать лишь как кастомный метод DOMElement'a.
Да и, скажем, вероятность ошибки появляется. Повесим ненароком onclick на этот виджет в процессе исполнения кода, и всё сломается.
Нет, ошибок не будет, если события вешаются ТОЛЬКО в компонентах. js ядро находит элемент до инициализации обрабатывает onclick и стирает все упоминания о нем. Дальше в компонент попадает чистенькая dom node.
Я правильно понял, что все библиотеки загружаются в момент инициализации страницы?
Как, например, решается вопрос ленивой загрузки?
Тут все зависит от проекта, но.

Как правило, важно в разработке иметь мало маленьких файлов, а на продакшене один большой. В данном случае конфигом может быть не результирующий html, а шаблоны (так сделано на почте mail.ru). Синтаксис require простой и однозначный, поэтому написать на сервере скрипт, которых обходит шаблоны страниц и строит нужный js файл не сложно. Если что-то удаляется из шаблона это автоматом пропадает из собраного js.

Про ленивую загрузку. Эта задача решается параллельно и никак не противоречит подходу. Если в загруженном компоненте по таймауту или действию пользователя вызвать require, то все догрузится и выполнится. Более того если с сервера получить html размеченный компонентами, вставить его в дом и полученную ноду пропустить через инициализирующий скрипт, скрипт найдет компоненты, поймет что надо догрузить из еще не догруженного и все заработает из коробки.
В Mail.ru наконец-то изобрели виджеты? наверно все же использование onclick — тут не нужно, data-* точно так же работает даже в 6 IE. Доклад описывает какие-то устаревшие несколько лет назад подходы.

Обрабатывается ли у вас ошибка загрузки JS-файла? Обрабатываются ли JS-ошибки? Информируется ли о них пользователь? Или он сидит перед переставшей работать страницей и гадает, в чем дело?

Или еще тонкий момент. У вас есть метод observe(). Удаляются ли слушатели при удалении виджета из DOM?

По поводу скриптов — по мне, так проще в шаблонизаторе у виджета писать зависимости (хотя вы можете не согласиться конечно) вроде этого:

[widget type=«calendar»]
[dependencies]
[jsclass name=«CalendarController» /]
[css href=«calendar.css» /]
[/dependencies]
[body]
// html -код
[/body]
[/widget]

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

Еще момент. Если у вас информация о компоненте хранится в onclick, вам приходится в момент загрузки страницы обходить все дерево DOM в поисках таких компонентов. Также, при загрузке AJAX-контента надо его инициализирвоать. Это же неуклюже, и замедляет инициализацию страницы. Не проще ли назначить например уникальный id каждому виджету и при загрузке написать initWidgets([id1, id2, id3]). Мне кажется, это правильнее. Но опять же, кому как виднее.

Ну а если вы скажете, что то, что я пишу, сложно, нереализуемо, и т.д. Ок, ну посмотрите тогда как устроен фейсбук или вконтакте. А то, что вы расписали, тут, это каменный век клиентсайд разработки, не хватает еще хаков для netscape.
Вижу сарказм. Сразу говорю что зря. Я понимаю что хочется показать свое я, но это не профессионально. На первый раз отвечу с полной ответственностью, сделав вид что сарказм не заметил.

Подходы не устарели несколько лет назад, а появились несколько лет назад и эти годы показали что не зря.
Цитата из статьи «первый раз эту тему я освещал в 2007 году». За 5-ть с лишним лет методология выкристаллизовалась и стало понятно что лишнее, а что нет. Более того я в статье несколько раз говорил что если у вас возникла задача на client-side посмотрите на sever-side 99% она была решена еще в 60-х.

Про mail.ru, написано что придя в mail.ru я увидел что этими паттернами давно и активно пользуются, что меня еще раз порадовало.

Про ошибки это вообще отдельная большая тема, надеюсь расскажем. У нас в принципе мониторятся ошибки много и часто. Более того мы контактируем в той или иной степени с разработчиками браузеров. Опере посчастливилось иметь прямо представительство в России. Так вот из Вадима Макеева я пару раз душу вынимал по поводу багов оперы.

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

По поводу initWidgets([id1, id2, id3]), я выкинул это из статьи но упоминание такого подхода есть в видео. Это нормально и часто правильно, но это детали не меняющие подход.

По поводу фейсбук и остальных. Конкретно с разработчиками фейсбук я не общался, пока, но часто общаюсь с разработчиками лидирующих Российских сайтов, например Яндекс, разработчиками Google, NodeJS и т.д. Уж поверьте мы внимательно друг друга слушаем. Потому что не слушать разработчиков которые отвечают за работоспособность сайта перед 20 000 000 уникальных пользователей в день странно. Более того я внимательно выслушал вас и ответил. Поэтому, на будущее, в разговоре со мной не указывайте на решения других приводите в пример свои решения с продакшена.
Да, вы правы, с сарказмом я переборщил. Извиняюсь, что мой комментарий получился слишком язвительным и невежливым. Это, конечно, неправильно.

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

Также, несмотря на все красивые слова, на главной mail.ru куча скриптов и стилей просто вставлена в тело страницы, хотя наверняка они для всех пользователей одинаковы.
Главная не трогалась очень давно. И в принципе главная это не типичный проект.
Мы ее оптимизируем, но вставка скиптов и стилей не всегда плохо. Часть скиптов и стилей у нас в коде для того, чтобы пользователь как можно быстрее увидел некоторые блоки. В ущерб остальным.

Плюс есть портальная навигация, выносить стили и скипты в файлы из нее может быть плохим решением. Дело в том, что на сервере проекты берут портальную навигацию как кусок html из одного места с системой доставки и кеширования, а раздают сами (я про сервера). В случае вставки ссылок на скрипт весь mail.ru и одноклассники будут брать этот скрипт из одного места, а это опасно. Если что-то случается с этим сервером, то миллионы пользователей увидят побитые страницы.
Не поясните ли насчет очереди длиной в 1?
Насколько я понял, единичная длина очереди «прошедших» эвентов специфична именно для даты: наверное кроме события «change_date», редко что-то будет еще использоваться для оповещения отображения.

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

Может быть есть что рассказать про случаи с хранением очереди более 1?

Также интересна примерная реализаций этой очереди. Я так понимаю, в каждом observe надо сопоставить object c объектами эвентов в очереди (можно проверять на идеинтичность, а можно и на вложенность). Далее сэмулировать выработку эвента? Тогда может получиться, что этот эвент опять получат еще раз те, кто уже слушал до этого. Т.е. надо эмульровать только для конкретного слушатель, как вариант просто вызвать callback этого нового observe().
Спасибо.
Лично я выбрал такие значения:
0 — нет очереди
>0 очередь указанной длинны
-1 в принципе хранить все что пришло.

Но на практике мне кроме 0 и 1 ничего не понадобилось.

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

Про реализацию. Как только в callback приходит observe или dispatch я проверяют что у объекта нет __UNIQID и дописываю его используя инкрементирующийся счетчик. Если есть, то использую имеющийся. Дальше у вас есть __UNIQID строкой, имя события строкой и данные. Из первых двух составляется ключ, вторыми наполняется массив, длина которого ограниченна длинной очереди. Ключ указывает на массив.
Добрый день, Андрей. Про очередь было не очень понятно. Суть в том, что объект ответственный за предачу эвентов хранит последние n эвентов и при появлении нового подписчика высыпает ему их, при этом сохраняя информацию в очереди? (мне почему-то сначала казалось что очередь очищается при передаче сообщения слушателям).

В чем преимущество такого подхода перед простой «приостановкой» отдачи событий слушателям до полной инициализации страницы. Пока страница не инициализирована события пишутся в буффер, после инициализации раздаются, и больше буффер не используется. Мне кажется так проще и наглядней, но вы очевидно решение с очередью не просто так выбрали. Расскажете?
Еще есть аякс и инициализация объектов по действиям пользователя. Поэтому нет такого события, по которому однозначно можно понять что все компоненты проинициализировались и больше ничего не появится.
Да, так явно намного гибче. Спасибо.
Автор не будет так любезен раскрыть тему нет не сисек реализации очереди событий? Премного благодарен.
Вроде все выяснили в личной переписке.
Подразумевал конкретную реализацию методов объекта. Т.к. Вы уже учли большинство нюансов — многие не строили бы свои велосипеды, а видели бы сразу как надо.
Моя реализация шести или семилетней давности github.com/AndrewSumin/jsx/blob/master/CallBacks.js
Вопросик про инициализацию компонентов. Подход при котором компоненты помечаются определённым классом, а данные храняться в onclick (или кому-то больше нравится data-*) понятен.
Какие недостатки у варианта 2: сразу после html кода компонента в вёрстке вставляется тег script с вызовом функции ядра (которая точно уже загружена) initComponent(htmlId, data)?
Может это устарело или имеет очевидные недостатки? Спрашиваю, т.к. хочу понять best practice на сегодняшний день. Если дадите ссылку, что почитать про современные паттерны программирования клиентской части на JavaScript — спасибо.
Подход актуален иначе бы я его не рассказывал.
Дальше все зависит от ваших задач, если большой сайт с десятками страниц то очень советую.
Если страниц мало, то только накладные расходы.

Что касается инструментов, я бы посоветовал какой-нибудь requirejs.org/
Sign up to leave a comment.