Подскажите, как корректно передать данные из бэм-дерева в js? Например, для блока "товар" в интернет-магазине нужно передать ID товара.
Пока приходят в голову только варианты типа "отрендерить его на страницу" (например, в data-атрибуты). Но все равно не понятно, что делать, если даных много.
Если я правильно понял, что вам нужно, то первое, что приходит в голову, это не data атрибуты, а onclick
Вы должны понимать, что у вас есть дата и вариантов транспорта не много:
1. Как вы уже сами решили — это HTML в виде атрибутов в общем потоке (лучшее — видимо, onclick),
2. В общем потоке в HTML, но в виде inline js с JSON-данными, сложность в связи данных и отрисованных экземпляров блока,
3. В отдельном потоке (script/XMLHTTPRequest или как-то еще) — в этом случае нам нужно передать данные дважды — первый раз в bemjson то, что нужно видеть в исходном дереве, и в следующий раз тогда, когда объект при инициализации сходит еще раз на сервер и спросит web-api доп. данные для блока.
Естественно, вам не обязательно делать 1 запрос для каждого блока, вы можете собрать все нужные вам запросы и отправить их одним мультизапросом к вашему апи, которое поддерживает batch. А в bemhtml вам будет достаточно передать некий id, по которому блок сможет понять, что он такое в вашей бизнес модели, и правильно спросить АПИ.
АПИ, кстати, тоже можно вынести в отдельный блок без отображения. Ведь где-то оно должно жить, так ведь?
upd: Всегда в таких случаях рассматривайте все возможные варианты, их плюсы, минусы, и выбирайте наименьше зло.
Да и слова "данных много" несколько абстрактные — для вас 20 тысяч слов может быть много, когда для браузера 100КБ это обычное дело.
Спасибо за ответ!
Второй вариант тоже входит в способ "отрендерить на странице" (data-атрибуты - просто привел в качестве примера). А для третьего варианта все равно нужно как-то передать параметры запроса к API. Так что, получается, вариант всего один..
Под словами "данных много" имел в виду сложную структуру данных, а не количество информации.
Кстати, можете кратко рассказать о преимуществах onclick перед data-атрибутами?
Я, конечно, не тестировал, но очевидно, что как минимум 1 проход и много маленьких, но более-менее существуенный профит есть только в старых браузерах. Я бы не стал завязываться на HTML структуру, т.к. она не про блоки, она про отображение веб-страницы. На практике я видел много попыток использования data атрибутов, успешными были не более 5%, остальные только привнесли проблем.
Кроме того, если вам надо передать массив/список или хэш таблицу — в onclick вы передадите его как есть, когда как в data атрибутах вам придется придумать как его туда складывать и как забирать. Это существенное различие.
На самом деле, первый раз вы можете не знать о пользователе, нарисовать общую страницу и положить её в кеш nginx на фронтенде.
А когда пойдете за данными пользователя — перерисовать нужные куски на странице, не думая что там было до этого.
Вы же в курсе, что в onclick и лежат всякие данные про блок? Послушайте доклад Сергея Бережного http://tech.yandex.ru/eve nts/yasubbotnik/msk-jul-2 012/talks/302/
На структуру HTML и не нужно завязываться. Точнее, это не зависит от того, как рендерить данные. Можно добавить onclick любому элементу, а можно - наоборот - добавлять data-атрибуты только корневому тэгу.
В onclick нужно рендерить json. Его можно точно также отрендерить и в data-атрибуты.
Есть существенная разница. В IE6-9 data атрибуты придется парсить руками. Массивы и объекты (data-my-array="[1,2,3,{& quot:key":"valu e"}]") придется выбирать и прогонять дополнительно через JSON.parse.
Когда как onclick парсится при разборе документа и получается изи в один вызов метода: var data = node.onclick(
Итого: точно так же — нельзя.
Понятно. Спасибо за объяснения!
Я пока склоняюсь к рендерингу данных в отдельный js, связывать с экземпляром блока по уникальному идентификатору, который сохраняется в data-атрибут. В этом случае ничего не нужно парсить и относительно легко пользоваться (по сравнению с onclick - 2 строчки вместо 1).
onclick не нравится, т.к .похоже на костыль.
Это не костыль) Послушайте доклад. Там есть proof-of-concept
По словам BEM onclick даже бенчмарк нашелся)
http://jsperf.com/onclick-vs-dataset/4
кроме того, есть и обратная сторона медали:
http://jsperf.com/onclick-vs-dataset/6
В 6 ревизии теста в рантайме делается node.onclick = 'return ' + bemdata + ';'; и сравнивается с new Function. В общем-то, тоже очевидно, что на деле это одно и то же — eval. И так делать не надо.
Если нужно передать данные с сервера на фронт — onclick="return {}" самый лучший вариант. Но он не дает никакого профита, когда вы с помощью и без того медленного DOM дерева пытаетесь парсить JS на клиенте.
мм.. очень любопытно.
кажется, что тест 6, где DOM не только селектится но и генерится, показывает нам нижний предел.
но вставка кучи блоков по одному это какой-то панк, как мне кажется -- в реальности кучи блоков добавляются пачками, и трюк с onclick в таком случае должен быть эффективнее (вроде про это обычно говорят в презентациях?)
с другой стороны в 4 тесте DOM структура генерится в setup, в смысле "outside of the timed code region". поэтому, что считает тест onclick() тоже не понятно. на этапе исполнения JS блоки инициализируются быстрее, но какова цена за это при первоначальном парсинге html, который за скобками теста? не получается-ли так, что при загрузке больших страниц, неотключаемый авто-парсинг onclick сводит "на нет" все преимущества live-инициализации?
до знакомства с i-bem я был уверен, что идеологически правильным способом для записи данных на странице является html (тогда еще html4). т.е. если какой-то там динамической штуковине нужны какие-то специфичные данные, то они должны быть представлены (отрендерены) на странице. атомарные значения могут быть преставлены атрибутами или тегами, более сложные - структурой тегов. для разных случаев разные идеомы, семантика, кои без конца выдумывает w3c. например табы:
теперь же про все это можно, практически, не думать. любые структуры, которые только можно себе представить можно записывать в "js": {}, и шаблонизатор автоматически нарисует все это просто и красиво:
жить стало гораздо проще. серьезно, если не думать ни про семантику, ни и то, как оно будет вести себя с отключенным js, ни про всякую WAI-экзотику, которой w3c морочит нам голову -- верстка становится абсолютно дешманским делом. %)
Много букв Сорри.
Да, тест 6 нам это и показывает. но это и правильно, и логично. При вставке кода в параметр мы все равно заставляем браузер распарсить код в функцию. фактически, браузер внутри делает что-то вроде new Function (string), которую мы и передали в onclick = string. но кроме того, что браузеру надо это парсить — мы еще и работаем с DOM, запись в который сама по себе не быстрая по разным причинам.
А в тесте 4 — это как раз случай, который показывает, что onclick уже разобран и браузер просто выполняет функцию без доп. eval. Да, разбор страницы это чуть медленнее, но это настолько же быстро, если не быстрее, чем делать new Function, или пару JSON.parse и несколько getAttribute.
В любом случае, очевидный профит в IE, и
Вообще, думать об этом стоит меньше, это выполняется единожды, а совсем небольшую выгоду в нормальных браузерах искать — они и так достаточно быстрые. Да, в них есть dataset — но сам dataset тоже требует CPU. И смотрите на те браузеры, которые не знают про dataset — IE6-10, там это будет работать и медленнее, и придется завязываться на $.data, или JSON, или делать eval с new Function, или даже просто перебирать неведомые структуры через getAttribute. Стоит это того? Врядли.
Сводит ли на нет парсинг onclick? А подгрузка и парсинг i-bem библиотеки сводит на нет live-инициализацию?) Вопрос из той же серии, только тут небольшой кусок кода, а там большой, и тут не надо ничего тянуть из сети и ждать — работа с I/O самый большой bottleneck в браузере (да и много где).
Основная проблема, при чем, в том, что соединение обрывается — данные летят быстро, но TCP/IP соединение устанавливается очень медленно, и часто затем закрывается. А держать соединения открытыми — тоже накладно, т.к. есть свои ограничения на порты. Браузеры и веб-сервера пытаются оптимизировать (и у них получается) с помощью Keep-Alive заголовка, который говорит веб серверу, что через одно соединение пролетит несколько запросов, но после этих запросов соединение все равно закрывается, и открывается новое.
Хотя я вот думаю, что не хватает теста на запуск:
Возможно, eval все-таки делается каждый раз.
Можно же так или так:
даже без присваивания куда-либо.
Ну да, кучка толстая будет, но who cares если эта информация нужна на этой конкретной странице и только?
Вот тут я не понял. А зачем нам совать данные в onclick, если мы на морде рисуем html? У нас же данные в памяти уже, зачем их еще раз прогонять через парсер и все эти лишние телодвижения?
и это в зависимости от используемой базовой библиотеки автоматически отрендерится либо в onclick (в bem-bl), либо data-атрибут (в bem-core).
А i-bem.js в свою очередь умеет вынимать эти параметры через this.param('ID').
Аналогично параметры могут быть и у элементов.
PS: Переход на использование data-атрибутов в bem-core произошел с подачи Марата Дулина, который обнаружил ошибку в старых бенчмарках и доказал, что парсинг data-атрибутов работает быстрее, чем onlick.
любое универсальное решение это компромисс. где-то лучше, где-то хуже. не IE единым. в телевизорах его нет например, но там свои кошмары - недо-браузер, медленный процессор и ограничения по памяти.
использование onclick не только сокращает время инициализации js, но и приводит к увеличению времени парсинга html (до заветного 'domready').
за счет live-инициализации мы сокращаем время на инициализацю js. но onclick парсятся без относительно этго. если опциональных блоков на странице много (что типично для SPA), выгоднее лапками распарсить, только те данные, которые нужны прямо сейчас.
было бы круто иметь возможность выбирать стратегию рендера и парсинга данных.
Судя по логам speed tracerа, webkit первый раз парсит onclick, второй раз использует колбек из кеша. При чем, у меня показало 25% на парсинг HTML, 25% на eval, и 50% на вызов колбека.
Т.е. прекратите панику, парсинг onclick происходит ondemand.
upd: можно поднять две странички: одну с кучей js в onclick, вторую — с data-bem с той же строкой без return. и сравнить время между первым алертом и domready. например, так:
JS в атрибуте должно быть очень много. Если время будет сильно отличаться (больше, чем на 5%), то смысл обсуждать это есть Если же время будет примерно одинаковое — значит мы испугались того, чего нет.
Ха. А где-то опубликовано доказательство? Было бы интересно ознакомится