История и текущее состояние популярного подхода к разработке Web-приложений

Эта статья содержит введение в AJAX-программирование и знакомит с реализацией AJAX на основе базового JS-кода и на основе различных библиотек. В статье рассказана краткая история технологии и представлены технические основы использования AJAX с помощью базового JS-кода и трех популярных JS-библиотек.

За последние несколько лет язык JavaScript прошел путь от «вечно отстающего» и объекта насмешек до ключевого языка Web-программирования. Если попытаться выделить ключевой фактор, способствовавший росту популярности JavaScript, то это появление приложений на основе технологии AJAX.

Наработка навыков использования JavaScript

Эта статья является частью курса по развитию навыков использования JavaScript.

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

Краткая история AJAX

История технологии AJAX, которая, казалось бы, мгновенно завоевала огромную популярность, похожа на историю других прорывных технологий. Хотя кажется, что эта технология появилась из ниоткуда, на самом деле для этого потребовалось определенное время. Несколько лет исследований в области Web-разработки привели к созданию инструментов и подходов, которые распространялись под «брендом» AJAX. Начиная с эры DHTML в период первоначального Интернет-бума и на протяжении "темных" лет после массового краха доткомов разработчики по всему миру открывали для себя неожиданные возможности JavaScript, открывающие новые пути для разработки Web-приложений.

XMLHttpRequest

Первый и самый важный компонент технологии AJAX – это XMLHttpRequest (XHR) API. XHR – это JavaScript API для передачи данных в виде сообщений между Web-браузером и Web-сервером. Этот API позволяет использовать HTTP POST-запросы (для передачи данных на сервер) и GET-запросы (для загрузки данных с сервера в фоновом режиме). XHR – это "ядро" большинства AJAX-вызовов и одна из важнейших технологий в современном Web-программировании.

Наконец, XHR - это лучший подарок Интернет-сообществу, сделанный командой Microsoft® Internet Explorer®.

Это действительно так. XHR впервые появился в пятой версии Internet Explorer в 2000 г. Изначально написанный Алексом Хопманном (Alex Hopmann) в виде элемента управления Microsoft® ActiveX®, XHR был создан для использования в Microsoft Outlook® Web Access и предназначался для "сглаживания" взаимодействия между передовым для того времени пользовательским интерфейсом и Microsoft Exchange Server.

Хотя пакет от Microsoft нельзя считать скромным началом, но XHR определенно переросл рамки исходного продукта. С тех времен XHR был интегрирован во все основные Web-браузеры и даже был признана W3C в качестве стандарта.

Первооткрыватели

Помимо реализации от Microsoft, другие компании также предпринимали попытки развития в направлении AJAX. Хотя с подобными технологиями экспериментировали многие, стоит особо отметить два проекта: первый, потому он стал интересной и часто упоминаемой вехой в истории развития AJAX, и второй, который сделал технологию AJAX действительно массовой.

Oddpost

Oddpost — это функционально насыщенный Web-клиент для электронной почты, выпущенный в 2002 году. В нем использовались многие подходы, сохранившие популярность и по сей день. По стилю и функциональности он напоминал стандартный клиент для работы с электронной почтой. Но в его реализации применялась технология DataPacks, позволяющая передавать небольшие фрагменты данных между сервером и Web-браузером. В то время такое решение считалось инновационным.

В дальнейшем Oddpost был куплен компанией Yahoo! и использовался в качестве основы при создании обновленной версии Yahoo! Mail.

Google Maps, Google Suggest, Gmail и одна важная статья

Видимые изменения начались несколько лет назад с появления Gmail, Google Suggest и Google Maps. Все эти проекты интенсивно использовали AJAX-подход и радикально изменили область разработки Web-приложений. Их отзывчивость и интерактивность поразили рядовых пользователей, и продукты Google быстро завоевали популярность у активной части Интернет-сообщества.

Хотя не все об этом знали, но область разработки Web-приложений ожидали еще более значительные изменения. Пользователи понимали, что Web-приложения меняются и приобретают новые замечательные возможности, но в чем конкретно заключаются эти изменения, было неизвестно.

Однако хватило одной статьи, чтобы "открыть глаза" Интернет-сообществу на суть происходящих изменений.

18 февраля 2005 года Джесси Джеймс Гаррет (Jesse James Garrett), сооснователь и президент компании Adaptive Path, написал статью "Ajax: A New Approach to Web Applications". В этой статье он описал подход к разработке Web-приложений, который уже использовался в таких приложениях, как Gmail и GoogleMaps. Он назвал это "фундаментальным сдвигом в возможностях, доступных Web-приложениями".

Также он дал название данному подходу. Это важно, так как новый термин сфокусировал внимание сообщества на самом тренде и стал отправной точкой для обсуждения новых возможностей разработки Web-приложений. В статье Гаррета термин AJAX описывался следующими словами.

Определение AJAX
AJAX — это не технология. На самом деле AJAX — это новое объединение нескольких технологий, каждая из которых сильна в своей области. AJAX включает в себя:
  • стандартное представление с помощью XHTML и CSS;
  • динамическое отображение и интерактивность благодаря DOM;
  • обмен и манипулирование данными с помощью XML и XSLT;
  • асинхронное получение данных с помощью XMLHttpRequest;
  • использование JavaScript для интеграции вышеперечисленных технологий.

Хотя это техническое описание несколько устарело, основная идея сохранилась: HTML и CSS представляют данные и стиль; DOM и связанные с ней методы позволяют обновлять страницу в режиме реального времени, XHR отвечает за общение с сервером, а JavaScript управляет процессом в целом.

Общий эффект от этой статьи был ошеломительным. Она представляла собой редкий случай, когда рекламные обещания, объединившись с огромной креативной энергией, действительно привели к революции. Подхваченная новым поколением стартапов, которые начали появляться по всему миру, технология AJAX быстро оказалась на передовой линии Web-разработки. Эта технология прошла путь от тренда с неясной маркетинговой перспективой до ключевого компонента современных Web-дизайна и Web-разработки.

Библиотеки

Одним из ключевых факторов, способствовавших развитию Web-разработки на основе AJAX, стало появление и внедрение нескольких высокофункциональных JS-библиотек. За исключением опытных JS-разработчиков мало кто в действительности понимал, как работают технологии, формирующие AJAX. Поэтому, хотя многие аспекты интерактивности и анимации внутри Web-браузера в эпоху DHTML были доведены почти до предела возможного, сложность использования AJAX привела к большому разрыву между потребностями в Web-сайтах с AJAX-возможностями и количеством людей, способных создавать такие интерфейсы с нуля. Библиотеки, подобные Prototype, Dojo и jQuery, помогли преодолеть этот разрыв, предоставив готовую функциональность, которая позволила реализовать анимацию и интерактивность, преодолеть различия между Web-браузерами и сгладить недостатки базового JavaScript API.

Асинхронный JavaScript и не только

Одним из крупнейших изменений в мире AJAX с момента его зарождения и до сегодняшнего дня стало появление JSON - протокола для обмена данными на основе JavaScript. JSON, благодаря небольшому объему передаваемой информации и удобному доступу с помощью родного JavaScript API (в отличие от сложных методов и свойств, основанных на DOM и XML), был быстро принят разработчиками в качестве стандартного транспортного протокола. С момента своего появления JSON также успел попасть в последнюю 5-ую версию спецификации ECMAScript.

JSON+Padding

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

Но, несмотря на свою популярность, JSONP обладает очевидной уязвимостью, которой могут воспользоваться злоумышленники. Возможность «инъекции» тега script со стороны позволяет выполнить на базовой странице любое действие, что создает невероятные возможности для нанесения вреда пользователям, если источник данных был скомпрометирован или основной Web-сайт не интересуется происхождением ресурсов, добавляемых на его страницы.

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

XMLHttpRequest API и его возможности

Хотя помимо XHR существуют и другие подходы для получения данных с сервера, именно XHR остается "ядром" большинства AJAX-приложений. Взаимодействие на основе XHR строится на двух компонентах: запрос и ответ. Ниже будут рассмотрены обе эти составляющие.

Модель безопасности

Как уже говорилось, исходный объект XMLHttpRequest обладает четкой моделью безопасности. Политика "same-origin" (объекты, происходящие из одного места) позволяет взаимодействовать только с тем хостом, протоколом и портом, которые использовались запрошенной страницей. Это означает, что общение между различными доменами (example.com и example2.com), различными хостами (my.example.com и www.example.com) и различными протоколами (http://example.com и https://example.com) запрещено и приводит к возникновению ошибки.

Однако благодаря разработке консорциумом W3C второй версии XHR-объекта и нового протокола Cross-origin Request Protocol и реализации этих концепций в большинстве Web-браузеров, включая InternetExplorer 8+, Mozilla Firefox 3.5+, Apple Safari 4+ и Google Chrome, появилась возможность выполнять запросы между доменами. Хотя для этого и потребовалось время, но теперь, указав в запросе специальный заголовок Origin:

Origin: http://example.com

и настроив сервер отправлять обратно соответствующий заголовок Access-Control-Allow-Origin:

				Access-Control-Allow-Origin: :
				http://example.com

стало возможным осуществлять дуплексное взаимодействие между доменами с помощью XHR-объектов.

Запрос (request)

Со стороны запроса доступны следующие четыре метода:

  • open() – открывает подключение к серверу и принимает несколько аргументов:
    • method - используемый HTTP-метод (допускается POST или GET)
    • url - запрошенный URL-адрес.
    • async - необязательный Boolean-параметр, сигнализирующий о том является ли запрос асинхронным или нет (по умолчанию равенTrue).
    • user – необязательный параметр, содержащий имя пользователя для аутентификации.
    • password – необязательный параметр, содержащий пароль, используемый для аутентификации.
  • setRequestHeader() – устанавливает заголовки запроса и принимает два аргумента: header (имя заголовка) и value (значение заголовка).
  • send() – отправляет запрос и может принимать необязательный параметр, содержащий тело POST-запроса.
  • abort() – прерывает отправку запроса.

Ответ (response)

Объект response также обладает определенными атрибутами и методами:

  • status – стандартный HTTP-статус запроса (например, в случае успешного выполнения запроса будет возвращено значение 200).
  • statusText – строка, содержащая полное описание статуса, возвращенного Web-сервером (например, 304 Not Modified).
  • getResponseHeader() – возвращает значение определенного заголовка ответа; в качестве параметра принимает имя запрашиваемого заголовка.
  • getAllResponseHeaders() – возвращает текстовое содержание всех заголовков ответа.
  • responseText – атрибут, в котором хранится текстовое представление тела запроса.
  • responseXML – атрибут, содержащий XML-представление тела запроса – фрагмент документа с DOM и всеми соответствующими методами.

Состояние readyState

После создания объект XMLHttpRequest может находиться в одном из пяти состояний, перечисленных ниже:

  • 0: UNSENT – объект только что был создан.
  • 1: OPENED – был успешно вызван метод open() данного объекта.
  • 2: HEADERS_RECEIVED – заголовки ответа были успешно загружены.
  • 3: LOADING – тело ответа загружается.
  • 4: DONE – запрос был выполнен, но неизвестно – успешно или нет (информацию о результате выполнения запроса можно получить с помощью стандартных статусов и заголовков HTTP-ответа).

Пример, использующий базовый JavaScript API

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

Листинг 1. Пример HTML-документа
<!doctype html>
<html lang="en"> 
<head>
  <meta charset="utf-8">
  <title>Простой AJAX-пример</title>
  <meta name="author" content="Rob Larsen">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="/_assets/css/style.css">
</head>
<body>
    <div id="main">
        <h1>Простой AJAX-пример</h1>
        <p><strong id="activate">Нажмите здесь</strong> 
            и после этого параграфа появится новый текст</p>
    </div>
	<script src="/_assets/js/ajax.js"></script>
</body>
</html>

В листинге 2 представлен простой GET-запрос, обрабатывающий объект responseXML. Этот пример AJAX-вызова выполнен в духе первых лет этой технологии, но он работает во всех современных Web-браузерах, включая Internet Explorer версий 7 и 8.

Листинг 2. Базовая AJAX-функция
/*
базовая AJAX-функция
*/
var ajax = function( opts ) {
/*
в объекте opts передаются аргументы функции;
для пропущенных аргументов будут использоваться значения по умолчанию.
*/
  opts = {
      //тип запроса: GET или POST
      type: opts.type || "POST",
      //URL, на который необходимо отправить запрос, или пустая строка
      url: opts.url || "",
      //что необходимо сделать с полученными данными?
      //если явно не указано, то вызывается функция function()
      onSuccess: opts.onSuccess || function(){},
      //какого типа данные должен вернуть сервер?
      //если явно не указано, то считается, что сервер должен вернуть XML-документ
      data: opts.data || "xml"
  };
//создание нового объекта XMLHttpRequest
  var xhr = new XMLHttpRequest();
//установка соединения с сервером
  xhr.open(opts.type, opts.url, true);
/*
когда состояние запроса изменится, то вызвать указанную функцию
*/
  xhr.onreadystatechange = function(){
  //значение атрибута readyState, равное 4, говорит о том, что запрос был выполнен
    if ( xhr.readyState == 4 ) {
  /*
  обработка полученных данных
  в возвращенном объекте могут содержаться два компонента: 
  responseXML и responseText. 
  в зависимости от того, что ожидалось получить, выполняются определенные действия
  */
    switch (opts.data){
        case "json":
            //json – это текстовые данные
            opts.onSuccess(xhr.responseText);
            break;
        case "xml":
            //XML-документ содержит в себе DOM-структуру 
            //этот объект передается целиком.
            opts.onSuccess(xhr.responseXML);
            break;
        default : 
            //все остальные варианты обрабатываются как текстовые данные
            opts.onSuccess(xhr.responseText);;
      }          
    }
  };
  //закрыть соединение
  xhr.send(null);
}
//функция по умолчанию, используемая для обработки полученных данных
var ajaxSample = function(e){
//полученный текст просто добавляется на страницу
  var callback = function( data ) {
    document.getElementById("main").innerHTML += 
      "<p>"
      +data.getElementsByTagName("data")[0].getAttribute("value")
      +"</p>";
}
//непосредственный AJAX-вызов
  ajax({
      type: "GET",
      url: "_assets/data/ajax-1.xml",
      onSuccess: callback,
      data : "xml"
   })
//отключение действия по умолчанию
  e.preventDefault();
}
//интеграция всех компонентов в единое целое
document.getElementById("activate").addEventListener("click", ajaxSample, false);

В листинге 3 используется оригинальный ActiveX объект. В случае, если его реализация отсутствует, с помощью блока try … catchвыполняется поиск потенциальных ссылок на этот объект в других версиях Internet Explorer. Этот пример полностью совместим с различными версиями Web-браузера Internet-Explorer начиная с версии 5.

Листинг 3. AJAX-сценарий, совместимый с различными Web-браузерами семейства IE
var ajax = function( opts ) {
  opts = {
    type: opts.type || "POST",
    url: opts.url || "",
    onSuccess: opts.onSuccess || function(){},
    data: opts.data || "xml"
  };
/*
поддержка исходного ActiveX объекта в старых версиях Internet Explorer.
этот код работает для всех версий IE, начиная с 5-й.
*/
  if ( typeof XMLHttpRequest == "undefined" ) {
    XMLHttpRequest = function () {
      try { 
          return new ActiveXObject("Msxml2.XMLHTTP.6.0"); 
      }
      catch (e) {}
      try { 
          return new ActiveXObject("Msxml2.XMLHTTP.3.0"); 
      }
      catch (e) {}
      try { 
          return new ActiveXObject("Msxml2.XMLHTTP"); 
      }
      catch (e) {}
      throw new Error("No XMLHttpRequest.");
    };
  }
  var xhr = new XMLHttpRequest();
  xhr.open(opts.type, opts.url, true);
  xhr.onreadystatechange = function(){
    if ( xhr.readyState == 4 ) {
      switch (opts.data){
    	case "json":
          opts.onSuccess(xhr.responseText);
          break;
        case "xml":
          opts.onSuccess(xhr.responseXML);
          break;
        default : 
          opts.onSuccess(xhr.responseText);;
      }          
    }
  };
  xhr.send(null);
}
var ajaxSample = function(e){
  var callback = function( data ) {
    document.getElementById("main").innerHTML += "<p>"
      +data.getElementsByTagName("data")[0].getAttribute("value")
      +"</p>";
  }
  ajax({
    type: "GET",
    url: "_assets/data/ajax-1.xml",
    onSuccess: callback,
    data: "xml"
   })
  e.preventDefault();
}
document.getElementById("activate").addEventListener("click", ajaxSample, false);

В листинге 4 приведен подход, чаще всего используемый сегодня: получение объекта responseText в формате JSON и преобразование его в "родной" JS-объект. Как видно из примера, работать с JSON-данными очень просто. Если сравнить этот листинг с порой неочевидными и многословными методами обработки XML-данных, станет ясно, почему большинство разработчиков в качестве транспортного протокола выбрали именно JSON.

Листинг 4. Использование JSON
var ajax = function( opts ) {
  opts = {
    type: opts.type || "POST",
    url: opts.url || "",
    onSuccess: opts.onSuccess || function(){},
    data: opts.data || "xml"
  };
  var xhr = new XMLHttpRequest();
  xhr.open(opts.type, opts.url, true);
  xhr.onreadystatechange = function(){
    if ( xhr.readyState == 4 ) {
      switch (opt.sdata){
        case "json":
          opt.onSuccess(xhr.responseText);
          break;
        case "xml":
          opt.onSuccess(xhr.responseXML);
          break;
        default : 
          opt.onSuccess(xhr.responseText);;
      }          
    }
  };
  xhr.send(null);
}
var jsonSample = function(e){
  var callback = function( data ) {
    //полученные данные на самом деле являются строкой
    //метод JSON.parse используется для превращения строки в объект
    data = JSON.parse(data);
    /*
    после этого можно использовать обычные JS-ссылки для доступа к данным
    */
    document.getElementById("main").innerHTML += "<p>"
      + data.sample.txt 
      +"</p>";
  }
  ajax({
    type: "GET",
    url: "_assets/data/json-1.json",
    onSuccess: callback,
    data : "json"
   })
  e.preventDefault();
}
document.getElementById("activate").addEventListener("click", jsonSample, false);

Во всех последующих листингах (с 5 по 11) используются JSON-данные.

В листинге 5 приведен простой пример JSONP. Как можно заменить, в нем полностью игнорируется XHR, а к сценарию просто добавляется callback-аргумент. Когда callback-вызов срабатывает (сервер возвращает ответ), полученный объект с данными помещается в исполняемый JS-код.

Листинг 5. Пример использования JSONP
var callback = function( data ) {
  document.getElementById("main").innerHTML += "<p>"+ data.sample.txt +"</p>";
}
var jsonpSample = function(e){
//создать элемент script
  var jsonp = document.createElement("script");
//установить значение атрибута source для созданного элемента script
//оно равно строке запроса с добавленным в конец callback-вызовом
  jsonp.src= "_assets/data/jsonp.php?callback=callback";
//добавить созданный элемент в документ
  document.body.appendChild(jsonp);
  e.preventDefault();
}
//привязать элемент script к определенному событию
document.getElementById("activate").addEventListener("click", jsonpSample, false);

Использование AJAX-библиотек

Для большинства программистов внутренняя структура AJAX-запроса интересна только с академической точки зрения, так как основная часть их работы выполняется в контексте одной или нескольких JS-библиотек. Кроме решения проблем совместимости между различными Web-браузерами, библиотеки также предоставляют функциональность, надстроенную над базовым API. В следующих примерах показывается, как выполнять GET- и POST- запросы с помощью API трех наиболее популярных библиотек.

jQuery

Сначала рассмотрим пример, использующий популярную библиотеку jQuery. Поддержка AJAX в jQuery была не так давно переписана, чтобы добавить новую функциональность, описание которой выходит за рамки данной статьи. Однако общей чертой всех AJAX-запросов в jQuery является наличие объекта с конфигурацией, передаваемого функции в качестве аргумента. Стоит отметить, что в jQuery есть несколько удобных методов, таких как $.post и $.get, служащих для быстрого доступа к конфигурации стандартных запросов.

В листинге 6 приведен исходный код, выполняющий загрузку данных с помощью jQuery.

Листинг 6. Реализация GET-запроса в jQuery
/*
callback-функция – это обычная функция, 
которая будет запущена, когда сервер вернет данные;
эта функция сохраняется в переменной callback
*/
var callback = function( data ) {
/*	
функция добавляет текст в документ.
добавляемый текст берется из JSON-объекта, полученного с сервера.
*/
  $("#main").append($("<p />").text(data.sample.txt));
}
/*
AJAX-вызов привязывается к событию click
*/
$("#activate").click(
  function(){
//вызвать метод $.ajax с объектом конфигурации в качестве параметра
	$.ajax({
//необходимо отправить запрос типа GET
      type: 'get',
//на указанный URL-адрес
      url: '_assets/data/json-1.json',
//по возвращении данных вызвать callback-функцию
      success: callback,
//данные будут передаваться в формате JSON
      dataType: "json"
    })
  }	
)

В листинге 7 показано, как использовать POST-запрос для получения JSON-объекта. В данном случае для "разбора" полученных данных используется "родной" объект JSON. В документации jQuery говорится о том, что неподдерживающие Web-браузеры необходимо дополнить сценарием JSON2.js.

Добавление специального обработчика для ошибок позволяет обрабатывать как удачные, так и неудачные запросы. В jQuery для описания ошибки используются три аргумента, включая сам XHR-объект, что позволяет наладить надежную обработку ошибок.

Листинг 7. Реализация POST-запроса в jQuery
/*
объект, который необходимо отправить на сервер
*/
var myMessages = {
  positive : "Today is a good day",
  negative : "Today stinks",
  meh : "meh"
}
var callback = function( data ) {
  $("#main").append($("<p />").text(data.positive));
}
/*
настройка простого обработчика ошибок.
он не выполняет никаких корректирующих действий,
а просто выводит информацию об ошибке
*/
var errorHandler = function( xhr, textStatus, errorThrown ){
  throw new Error("There was an error. The error status was " + textStatus );
}
/*
здесь находится основная логика приложения
событие подключается к обычной кнопке.
*/
$("#activate").click(
  function(){
//вызвать метод $.ajax, передав в качестве параметра объект с конфигурацией
    $.ajax({
      //данные необходимо отправить в POST-запросе
      type: 'POST',
      //на указанный URL-адрес
      url: '_assets/data/post-responder.php',
      /*
      данные, которые необходимо отправить, переводятся в формат JSON
      jQuery предполагает использование "родного" JSON-формата
      или JSON2.js в неподдерживающих Web-браузерах
      */
      data: JSON.stringify(myMessages),
      //выполняется настройка callback-функции
      success: callback,
      //сервер должен вернуть данные, также в JSON-формате
      dataType: "json",
      //подключение обработчика ошибок, созданного ранее.
      error : errorHandler
      }
    )
  }
);

Dojo

Как будет видно из следующих примеров, библиотека Dojo способна на большее, нежели простое манипулирование DOM-объектом и отправка AJAX-запросов. Её возможности позволяют создавать самые сложные приложения, но все равно стоит изучить её API и с такой "начальной" позиции.

В Dojo есть две специальные AJAX-функции: xhrGet и xhrPost. Кроме того, для разбора полученных данных используется JSON-утилита, входящая в Dojo. В листинге 8 приведен пример создания GET-запроса.

Листинг 8. Реализация GET-запроса в Dojo
var callback = function( data ) {
//метод dojo.byId это alias для метода document.getelementById
  dojo.byId("main").innerHTML += "<p>"+ data.sample.txt +"</p>";
}
var getData  = function(){
//для GET-запросов используется метод xhrGet
dojo.xhrGet({
  //URL-адрес, куда будет отправлен запрос
  url: "_assets/data/json-1.json",
  //полученный результат должен обрабатываться как JSON-данные
  handleAs: "json",
  //callback-функция, вызываемая в случае успешного выполнения запроса
  load: callback
});
}
// метод connect используется для подключения событий
dojo.connect( dojo.byId("activate"), "onclick", getData );

В листинге 9 приведен пример обработки POST-запроса с конфигурацией обработчика ошибок.

Листинг 9. Реализация POST-запроса в Dojo
var myMessages = {
  positive : "Today is a good day",
  negative : "Today stinks",
  meh : "meh"
}
var callback = function( data ) {
  dojo.byId("main").innerHTML += "<p>"+ data.positive +"</p>";
}
var errorHandler = function(){
  throw new Error("We dun goofed.")
}
var postData  = function(){
 //для POST-запросов используется метод xhrPost
  dojo.xhrPost({
  //URL-адрес, куда будет отправлен запрос
    url: "_assets/data/post-responder.php",
  //полученный результат должен обрабатываться как JSON-данные
    handleAs: "json",
  //установка заголовков запроса
    headers: { "Content-Type": "application/json; charset=uft-8"},
  //использование JSON-утилиты для подготовки данных
    postData: dojo.toJson(myMessages),
  //callback-функция, вызываемая в случае успешного выполнения запроса
    load: callback,
  //callback-функция, вызываемая в случае возникновения ошибки
    error: errorHandler
  });
}
// метод connect используется для подключения событий
dojo.connect( dojo.byId("activate"), "onclick", postData );

Yahoo! User Interface (YUI)

В библиотеке YUI используется немного другой подход, отличающийся от рассмотренных ранее. При использовании YUI всегда возвращается XHR-объект полностью, а не только "разобранные данные", что обеспечивает лучший доступ к данным, хранящимся в запросе, и позволяет более гибко манипулировать ими. Также это значит, что программист должен знать особенности внутренней реализации XHR-объекта. В виде отступления от основной темы в примерах показывается, как использовать загрузочный модульYUI.use(), который хотя и не относится непосредственно к AJAX (за исключением загрузки модуля io), но заслуживает отдельного упоминания. В листинге 10 этот модуль в качестве аргументов принимает список из других YUI-модулей и callback-функцию. После запуска он создает пакет, в котором все необходимые модули содержатся в одном CDN-артефакте, загружаемом с Web-портала Yahoo! Content Delivery Network.

Листинг 10. Реализация GET-запроса в YUI
// создать новый экземпляр YUI и заполнить его требуемыми модулями.
YUI().use('node','event', 'json', 'io', function (Y) {
  var callback = function( id, xhr ) {
    var data = Y.JSON.parse(xhr.responseText);
    Y.one('#main').append("<p>" 
      + data.sample.txt 
      +"</p>");
  }
  Y.one("#activate").on('click',
    function(){
      Y.io( '_assets/data/json-1.json', {
    	method: 'get',
    	on:   {success: callback}
      })
    }	
  )
});

В листинге 11 приведен пример реализации POST-запроса, в котором используется интересный приём: выделение функций для обработки запроса в отдельный объект on.

Листинг 11. Реализация POST-запроса в YUI
YUI().use('node','event', 'json', 'io', function (Y) {
  var myMessages = {
    positive : "Today is a good day",
    negative : "Today stinks",
    meh : "meh"
  }	
  var callback = function( id, xhr ) {
    var data = Y.JSON.parse(xhr.responseText);
    Y.one('#main').append("<p>" 
      + data.positive 
      +"</p>");
  }
  var errorHandler = function( id, xhr){
    throw new Error("возникла ошибка со статусом: " 
      + xhr.statusText 
      +".")
  }
  Y.one("#activate").on('click',
    function(){
      Y.io( '_assets/data/post-responder.php', {
    	method: 'post',
    	//использование утилиты Y.JSON для преобразования объекта messages в строку
    	data : Y.JSON.stringify(myMessages),
    	//все методы для обработки запроса инкапсулированы в объекте on
    	on:   {success: callback,
    		failure: errorHandler }
      })
    }	
  )
});

Как можно видеть, базовые принципы, применяемые во всех листингах, в целом совпадают. За исключением поддержки ActiveX-компонентов и JSONP, все примеры охватывают одну и ту же область, отличаясь реализацией конкретных API, основанных на базовых возможностях JavaScript для создания интерактивных приложений.

Важно учитывать, что все эти библиотеки предлагают гораздо больше возможностей, не ограничиваясь стандартной реализации AJAX, описанной в статье. Хотя большинство задач, связанных с использованием AJAX, обычно решаются с помощью обычных GET и POST-запросов, все равно полезно знать, какие ещё возможности может предложить выбранная библиотека.

Заключение

После изучения основ и некоторых аспектов внутренней реализации AJAX можно уверенно переходить к созданию AJAX-сценариев для собственных Web-сайтов и приложений. Как и в случае с любой технологией, лучший способ изучить AJAX – это использовать его для решения практических задач, так что не стесняйтесь использовать или изменять примеры, представленные в этой статье. За последние несколько лет выяснилось, что изучение AJAX – это крайне выгодное вложение ресурсов и времени.

Ресурсы

Научиться

Получить продукты и технологии

Роб Ларсен, архитектор интерфейсов, Isobar

Присоединяйтесь к нам в Твиттере.

Вверх