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

Несмотря на то, что Фрэнк пишет, что эти два подхода несовместимы, я обнаружил, что сам как раз их смешиваю, причем мне кажется что удачно :-).

Подробнее о подходах

Передача HTML

Подхода с передачей HTML'а идеально подходит для страниц, которые при взаимодействии с сервером меняются незначительно. Например некая форма, которая после сабмита на сервер опять появляется на экране, а вместе с ней либо рисуется картинка что все хорошо, либо рисуется список ошибок. В этом случае ajax позволяет сократить количество данных, передаваемых по сети, принимая с сервера не всю форму с индикацией, а только саму индикацию.

К несомненным плюсам этого подхода относится исключительная простота идеи, из которой прямо вытекает, что на клиентской стороне можно автоматизировать практически все:

Фактически все, что остается сделать программисту это:

К минусам подхода я бы отнес то, что он существенно хуже работает для "высокодинамических" страниц, где от одного действия меняются разные части. Например длинный тред комментариев, где по сабмиту формы с текстом с сервера должен прийти новый комментарий и, скажем, обновиться строчка "N комментариев", которая находится в совсем другом месте страницы. Здесь, если следовать автоматической модели, надо передавать на страницу ту ее часть, которая включает все нужные куски, даже если между ними есть данные, которые и не предполагались меняться. На практике это может привести к тому, что по сети гоняются немаленькие объемы данных, сравнимые с размером собственно страницы, и весь смысл ajax'а вырождается в отсутствие эффекта анимации иконки браузера в правом верхнем углу.

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

Передача структурных данных

Передача структурированных данных была сутью ajax'а еще когда он назывался "XmlHttpRequest". То есть он был придуман для того, чтобы обратиться на сервер и получить описание какой-то части состояния системы, выраженной в XML — языке, который предназначен для удобной машинной обработки. Сразу скажу, что несмотря на то, что так было задумано, свет клином именно на XML-ответах не сошелся, и структуру можно передавать и по-другому, о чем чуть позже.

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

Взять тот же пример с комментариями: на сервер отправляется комментарий, а в ответ возвращается например такое:

<comment status="ok" quantity="12"/>

Что означает, что комментарий прошел валидацию, и теперь их на странице 12. Все остальное можно сделать скриптом: пририсовать новый блок комментария, перекопировать туда текст формочки, фомочку удалить, обновить количество новой цифрой.

Самый очевидный минус в передаче структуры — это гораздо больший объем и сложность программирования. Причем складывается она из нескольких вещей.

Первая сложность — это использование XML'а. Несмотря на то, что формат четкий и замечательный, в Javascript'е с ним можно работать только с помощью методов DOM. А это муторно писать и очень сложно читать: слишком много текста для производства простых вещей. К счастью, этот конкретный недостаток в последнее время решился с помощью формата JSON: данные возвращаются с сервера не в виде XML, а в виде куска Javascript'ового кода создающего объект нужной вам структуры:

response = {
  status: 'ok',
  quantity: 12
}

Он тут же в скрипте выполняется eval'ом и вы получаете объект response, у которого есть response.status и response.quantity. Очень удобно и без всяких getElementsByTagName('response')[0].

Кроме убирания сложности разбора XML-ответа, остается вторая сложность: построение HTML полностью вручную DOM-методам, что, опять-таки, трудно и муторно.

Но самое плохое, что этим самым в системе появляются два совершенно разных места, в которых задается вид страницы: HTML-шаблон и Javascript'овый код. А значит изменения придется аккуратно дублировать и там, и там. И еще это значит, что для написания HTML'а вам теперь нужен человек, который умеет писать и HTML, и тяжелый Javascript. "Maintenance hell", иными словами.

Вообще, когда я начинал играться с XmlHttpRequest'ом, такой подход казался мне самым естественным: раз штука умеет парсить XML, значит это и есть правильный путь ее использования. Результатом тех упражнений стал довольно прикольный клиентский ajax-интерфейс к чату с множеством всяких фенечек. Тогда, в 2003 году, он был жутко передовым технологически, но раскрутить его во что-то известное мы так и не сподобились. Я даже удивился сейчас, что он до сих пор работает. Пусть теперь тут ссылочка для истории лежит :-)

Объединение лучших черт

Та несовместимость, о которой говорит Фрэнк Соммерс, присутствует только с точки зрения программиста, который выбирает передачу HTML, и не хочет погружаться в скриптование вообще. Однако если программист не против этого принципиально, то передачу структуры вполне можно объединить с передачей HTML'а. Принцип, на самом деле, очень простой:

Другими словами, вся "великая идея" заключается в том, что надо отказаться от догмы "пользоваться только XML'ом" и пользоваться тем, чем удобно.

Единственное, что мне пока не нравится в этом подходе, это то, что на серверной стороне несколько увеличивается объем работы. Если без ajax'а код, обслуживающий POST в форму, отдает всего два ответа — либо эту же форму с ошибками, либо редирект, когда все хорошо — то с ajax'ом к каждому ответу прибавляется еще вариант с выдачей JSON-объектов. Не особенно трудно, но выглядит слишком нагроможденно. Хотя со временем я надеюсь придумать или подсмотреть какую-нибудь автоматизацию этому процессу.

Комментарии: 17

  1. Elf

    Единственное, что мне пока не нравится в этом подходе, это то, что на серверной стороне несколько увеличивается объем работы. Если без ajax’а код, обслуживающий POST в форму, отдает всего два ответа — либо эту же форму с ошибками, либо редирект, когда все хорошо — то с ajax’ом к каждому ответу прибавляется еще вариант с выдачей JSON-объектов.

    Как вариант, обработчик на сервере нужно отделить еще одним уровнем абстракции, т.е. он не будет генерить конкретный ответ, а подготавливать данные, а конкретный ответ - html или html+json (в случае ajax-запроса) - будет генерить парсер более низкого уровня.

  2. Andrey Fedoseev

    остается вторая сложность: построение HTML полностью вручную DOM-методам, что, опять-таки, трудно и муторно.

    Это не так трудно и муторно, как кажется на первый взгляд. В mochikit это делается достаточно просто.

  3. funlinks.ru

    "Два принципиально разных подхода к написанию ajax-приложений."

  4. Max Ischenko

    Кстати, встречал в продаже перевод отличной книги Ajax in Action. Рекомендую.

  5. BOLK

    Я делал "like AJAX"-чат, когда ещё XMLHTTPRequest и иже с ними не было. (стоит, например, в http://www.kzn.ru/chat2/ )

    подзагрузка делалась внутри скрытого FRAME и работало даже в Netscape Navigator 4.xx, это было мноооого лет назад :)

  6. Alexander

    Опубликовал с сайта ajaxpatterns два шаблона в переводе на русский, там как раз теория написана как с помощью скрытого фрейма передавать данные. )) Может кому пригодиться?

  7. Олег

    Рекомендую обратить внимание на разработку Дмитрия Котерова - http://dklab.ru/lib/Subsys_JsHttpRequest/

  8. Julik

    Последний вариант - это практически RJS-шаблоны
    на клиент просто высылается код, если надо вставлять куски готового HTML то они пререндерятся на сервере и отсылаются как строковые переменные JavaScript.
    Чистый JSON хорош когда хочется заморачиваться написанием полной клиентской части и поддерживать ее в здравии. Плохая тестируемость JS этому крайне не способствует.

  9. Михаил

    Первый вариант еще называется in-place update или AHAH (странно, почему не AJAH). Если нужно обновить несколько кусков, то можно сгенерировать и послать серию запросов на сервер, и обновить несколько элементов страницы. Это тоже автоматизируется довольно просто, при этом остается простота и универсальность серверного кода. Хочешь, рисуй разметку в ответ на обычный синхронный запрос, а хочешь, рисуй ее же в ответ на асинхронный запрос, разница только в наличии открывающего/закрывающего тегов . В случае же с XML или JSON серверный код затачивается под постобрабоку джаваскриптом на клиенте, и без джаваскрипта такая программа уже не работает.

  10. Иван Сагалаев

    В случае же с XML или JSON серверный код затачивается под постобрабоку джаваскриптом на клиенте, и без джаваскрипта такая программа уже не работает.

    Почему это? Приложение сначала пишется работающим на простых постах форм, и это никуд не девается. Потом на клиенте перехыватываются нужные сабмиты, и там пишется умная (или не очень) обработка пришедших JSON'ов. На сервере же добавляются вилки "if ajax отправить JSON else отправить всю страницу".

    То есть наличие чисто HTML'ного fallback'а совсем не связано с тем, что именно передается через асинхронные коннекты.

  11. Михаил

    Почему это? Приложение сначала пишется работающим на простых постах форм, и это никуд не девается.

    Двойная работа. Мало кто так делает.

  12. Иван Сагалаев

    Я бы насчет "мало кто" не стал так уверенно утверждать :-).

    Я, например, так делаю. Потому что работы, хоть и больше, но не в два раза: ajax'ом делаются удобные добавления, но не дублируется весь HTTP-функционал. Зато мы получаем сайт, который работает в 8.x Операх, например. Или в других более экзотических браузерах на каких-нибудь PDA.

  13. Juri

    ткнуть пальцем в то, по какой кнопке он хочет “сделать ajax”, и в какой блок на странице потом записать результат "

    В том контексте, в каком появилась эта фраза - это все-таки не ajax, а remote scripting в чистом виде.
    Я считаю, что все-таки нужно придерживаться правила - называть вещи своими именами

  14. Олег Кубанов

    JSON
    А я все делал иначе. Написал библиотеку для автоматической генерации DOM (HTML) по шаблону. Теперь для использования JSON мне достаточно просто вызвать функцию build(json,tag,str), где json-полученный с помощью eval объект, tag-узел DOM для генерации содержимого, srt-шаблон. Теперь работаю с JSON просто и быстро.
    p. s. Принимаю предложения о сотрудничестве

  15. vflash

    к подходу с использованием XML, стоит упомянуть XSLT. Использования XSL делает работу с XML также простой как и с вставками HTML

  16. Румянцев С.Л.

    При обработке здоровенного объема данных, полученных от XmlHttpRequest, DOM+JavaScript работают очень долго. Поэтому наиболее перспективным способом, на мой взгляд, использовать связку XML+XSLT на стороне клиента. Это - облегчение работы сервера и полный контроль над визуализацией данных.
    Пример, работавший на клиенте IE-6:
    Получаемый объем 10 000 записей 7 полей
    DOM+JavaScript - 6 минут
    XML+XSLT - 5 секунд

  17. Денис

    Но самое плохое, что этим самым в системе появляются два совершенно разных места, в которых задается вид страницы: HTML-шаблон и Javascript'овый код. А значит изменения придется аккуратно дублировать и там, и там. И еще это значит, что для написания HTML'а вам теперь нужен человек, который умеет писать и HTML, и тяжелый Javascript. "Maintenance hell", иными словами.

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

    надо заверстать шаблонные куски.

Добавить комментарий