|
Это два года назад AJAX был в диковинку (да и самого слова AJAX тогда ещё не
выдумали). Теперь веб-приложения, страницы которых обновляются "на лету", в
порядке вещей. Даже наоборот, без AJAX трудно и представить себе некоторые
сервисы.
Как работали обычные веб-приложения? Как правило, на событие (клик по ссылке
или нажатие на кнопку) браузер реагировал отправкой запроса серверу. Когда с
сервера приходил ответ, всё содержимое страницы полностью обновлялось.
Одна из проблем состояла в том, что при обновлении содержимого страницы
веб-приложение переходит в новое состояние. Из информации о предыдущем состоянии
сохраняются только данные, переданные в запросе. Чем более точная информация о
прежнем состоянии системы требуется, тем больше данных необходимо пересылать в
запросе.
Другим недостатком является необходимость пересылать повторяющиеся массивы
данных клиенту после каждого события. Например, если пользователь ошибся при
заполнении формы, то вместо короткого сообщения об ошибке приходится снова
загружать и форму, и всю введённую ранее информации.
Современные браузеры, поддерживающие стандарты W3C DOM, позволяют вывести
веб-приложение на новый уровень.
Схема взаимодействия остается почти такой же. Вот только отправляет запрос и
получает ответ с сервера теперь скрипт на стороне клиента, а вместо обновления
всей страницы - обновляется только ее часть (вместо обновления могут
предприниматься иные действия, например, отправляться следующий запрос).
Веб-приложение получается распределенным, и часть логики находится на стороне
клиента, а часть - на стороне сервера. Такие приложения и называют термином "AJAX
Applications" (аббревиатура расшифровывается как Asynchronous Javascript And Xml
Applications).
Объект XMLHTTPRequest
Для асинхронных запросов от клиента к серверу на стороне браузера служит
специальный объект под названием
XMLHTTPRequest.
Перечислим методы и свойства объекта, которые будут использованы далее:
- XMLHTTPRequest.open("method", "URL", async, "uname", "pswd") – создает
запрос к серверу.
- method – тип запроса, например, GET
- URL – URL запроса, например http://localhost/file.xml
- async – если True, то будет использоваться асинхронный запрос, то
есть выполнение скрипта продолжится после отправки запроса. В противном
случае скрипт будет ожидать ответа от сервера, заморозив UI.
- uname, pswd – логин и пароль для простой веб-авторизации.
- XMLHTTPRequest.send("content") – отправляет запрос на сервер. Значением
content могут быть данные для POST-запроса или пустая строка.
- XMLHTTPRequest.onreadystatechange – обработчик событий срабатывающий на
каждое изменение состояния объекта. Состояния объекта могут быть следующими:
- 0 - до того как запрос отправлен (uninitialized)
- 1 - объект инициализирован (loading)
- 2 - получен ответ от сервера (loaded)
- 3 - соединение с сервером активно (interactive)
- 4 - объект завершил работу (complete)
- XMLHTTPRequest.responseText – возвращает полученные от сервера данные в
виде строки.
- XMLHTTPRequest.responseXML – если ответ сервера пришел в виде
правильного XML, возвращает XML DOM объект.
- XMLHTTPRequest.status – возвращает статус HTTP-ответа в виде числа.
Например, 404 если запрашиваемая страница не была найдена на сервере.
Рассмотрим применение объекта на примере простого AJAX-приложения.
Поле SELECT с поиском
Предположим у нас есть таблица, в которой порядка миллиона записей.
Пользователю необходимо выбрать всего одну запись из таблицы (реализация
отношения "один ко многим"). Выбор пользователя является всего лишь одним из
этапов заполнения большой веб-формы.
Естественно, для того, чтобы пользователь мог выбрать нужную запись из
миллиона, нужны какие-то средства поиска этой самой записи. Например, простой
текстовый поиск по наименованию.
В традиционном веб-приложении для этой цели пришлось бы использовать
отдельную страницу и сохранять остальные данные формы в сессии пользователя,
либо разбивать процесс заполнения формы на несколько этапов. В AJAX-приложении
дополнительная страница не нужна.
Выбор записи будет реализован с помощью двух элементов веб-формы. Первый
элемент - это текстовое поле, где пользователь вводит ключевое слово. Оно
отсылается на сервер, а тот возвращает только те строки из таблицы, которые
удовлетворяют условию поиска. Ответ сервера (в виде списка) помещается в поле
SELECT, в котором пользователь и сделает окончательный выбор. Таким образом, при
отправке всей формы на сервер попадет выбранное в поле SELECT значение в виде ID
записи из большой таблицы.
В HTML выглядеть это может так:
<input type="text"
onkeyup="lookup(this.value, 'id_select',
'http://localhost/cgi-bin/xmlhttp.cgi')" />
<select id="id_select" name="id_select">
<option selected="selected" value=""></option>
</select>
На любое событие KeyUp (отжатие кнопки) в текстовом поле вызывается функция
lookup ('текст', 'id-selecta', 'url')
function lookup(text, select_id, url) {
// Получаем объект XMLHTTPRequest
if(!this.http){
this.http = get_http();
this.working = false;
}
// Запрос
if (!this.working && this.http) {
var http = this.http;
// Если в текстовом поле менее трёх
// символов – не делаем ничего
if (text.length <3 ) return;
//добавляем закодированный текст
//в URL запроса
url = url + "?text="+encodeURIComponent(text);
//создаём запрос
this.http.open("GET", url, true);
//прикрепляем к запросу функцию-обработчик
//событий
this.http.onreadystatechange = function() {
// 4 – данные готовы для обработки
if (http.readyState == 4) {
fill(select_id, http.responseText);
this.working = false;
}else{
// данные в процессе получения,
// можно повеселить пользователя
//сообщениями
// ЖДИТЕ ОТВЕТА
}
}
this.working = true;
this.http.send(null);
}
if(!this.http){
alert('Ошибка при создании XMLHTTP объекта!')
}
}
Как видно, в начале мы получаем XMLHTTP-объект с помощью функции get_http().
Затем поисковый текст кодируется в стиле URL и формируется GET-запрос к серверу.
URL запроса в данном случае будет выглядеть приблизительно так:
http://localhost/cgi-bin/xmlhttp.cgi?text=...
Скрипт на сервере, получив значение text, делает поиск в таблице и отсылает
результат клиенту. В обработчике событий объекта XMLHTTP, когда данные от
сервера получены и готовы к использованию, вызывается функция fill('select_id',
'data'), которая заполнит список SELECT полученными данными.
Функция get_http() – это кросс-браузерная реализация получения объекта
XMLHTTP (в каждом браузере он получается по-своему). Её реализацию с
комментариями вы можете легко найти в интернете, это, так сказать, пример из
учебника.
function get_http(){
var xmlhttp;
/*@cc_on
@if (@_jscript_version >= 5)
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new
ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
@else
xmlhttp = false;
@end @*/
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
xmlhttp = false;
}
}
return xmlhttp;
}
Функция fill() получает на вход значение параметра ID списка SELECT, который
необходимо заполнить, и сами данные, полученные с сервера.
Для простоты предположим, что данные с сервера мы получаем в виде таблицы,
поля которой разделены символом табуляции 't', а строки - символом переноса
строки 'n':
id1 t name1 n
id2 t name2 n
...
На основании содержимого этой таблицы мы будем заполнять поле SELECT
элементами OPTION.
function fill (select_id, data){
// поле SELECT в переменную в виде объекта
var select = document.getElementById(select_id);
// очищаем SELECT
select.options.length = 0;
// если данных нет – не делаем больше ничего
if(data.length == 0) return;
// в массиве arr – строки полученной таблицы
var arr = data.split('n');
// для каждой строки
for(var i in arr){
// в массиве val – поля полученной таблицы
val = arr[i].split('t');
// добавляем новый объект OPTION к нашему SELECT
select.options[select.options.length]=
new Option(val[1], val[0], false, false);
}
}
Готово. Теперь для любой веб-формы приложения мы можем реализовать подобный
выбор значения из многомиллионного списка, который для пользователя будет
выглядеть как считанные нажатия клавиш. В локальной сети выбор происходит
практически мгновенно. В случае нестабильного или низкоскоростного соединения с
сервером, необходимо также оповещать пользователя о том, что загрузка данных с
сервера еще не завершена. Полезно предусмотреть и средства для реакции на обрыв
соединения.
Автор: Виталий Акулов, источник:
Компьютерра
|