Сверхдинамичные веб-интерфейсы

18 Август, 2008 - 02:02 Корбмахер Артем info@webinfo.kz

Одно из главных затруднений, вместе с которым сталкиваются разработчики интерфейсов веб-приложений, состоит в том, что именно потом того, как будто страница оказалась в браузере клиента, союз браузера вместе с сервером завершается. Любое деяние вместе с элементом интерфейса требует повторного обращения к серверу вместе с повторной загрузкой новой страницы. Из-за сего веб-приложение теряет свою элегантность а также неторопливо работает. В этой статье я расскажу об том, как будто данную проблему дозволено разрешить вместе с помощью JavaScript а также объекта XMLHttpRequest.

Я уверен, что именно вам знакома традиционная модель интерфейса веб-приложений. Пользователь запрашивает страницу вместе с сервера, которая на сервере создается, однако потом пересылается браузеру. Около этой страницы существует HTML-части, описывающие форму, в которую пользователь вводит данные. После сего пользователь отсылает данные на сервер а также получает новую страницу, основанную на введенных данных, а также процесс повторяется. Весь настоящийа#однако процесс определяется самой природой HTTP-протокола а также отличается от того, как будто все мы работаем вместе с обычными приложениями, интерфейс которых неразрывно связан вместе с программной логикой.

Возьмем простой пример ввода массового номера в каком-или Windows-приложении. В соответствии правилам, затем того, как будто вы закончите вводить замысловатый набор цифр а также букв в поля, рядом вместе с ними появится зеленая "галочка", означающая, что сейчас вы ввели безошибочный номер. Она появляется моментально, как будто итог логики "вшитой" в интерфейс. Как лишь только вы закончили наливать номер, программа проверяет его а также выдает ответ.

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

Разумеется отнюдь не зачастую веб-приложение требует от пользователя ввести серийный номер, только существует бесчисленное огромное количество иных примеров, в каком месте спешная реакция интерфейса на действия пользователя очень бы пригодилась. Же этак как будто вся программная логика лежит на сервере, принять подобный итог в традиционном веб-приложении очень трудно.
На сцене появляется JavaScript

Благодаря JavaScript определенное число программной логики дозволено перенести в HTML-страницу, что сейчас позволит скоро реагировать на действия пользователя. Однако около сего решения существует один основной изъян. Первая проблема заключается в том, что именно как будто лишь только JavaScript попадает в браузер пользователя совместно с страницей, программная логика доступна с целью просмотра невооруженным глазом. В случае к примеру вместе с проверкой правильности введенного адреса e-mail это вероятно быть а также никак не страшно, а ежели проверка соединена вместе с серийным номером, алгоритм проверки становится доступным всем, кто скачал страницу, однако это неприемлемо.

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

Решением этой проблемы вероятно начать объект XMLHttpRequest. Оныйа#Однако объект впервые был реализован компанией Microsoft в виде объекта ActiveX, а теперь он доступен как будто встроенный объект в всех браузерах Mozilla а также Safari. Нынешнийа#Но объект разрешает JavaScript-около осуществлять HTTP-запросы к удаленному серверу кроме необходимости перезагружать страницу. По сути HTTP-запросы отправляются а также получаются совсем за "кулисами" страницы, но пользователь их даже если далеко не замечает.

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

Из-за своей противоречивой истории объект XMLHttpRequest еще раз далеко не является частью какого-или стандарта (хотя нечто подобное уж было предложено в спецификации W3C DOM Level 3 Load and Save). Поэтому существует 2-ва отличных приятель от друга метода вызова сего объекта в коде скрипта. В Internet Explorer объект ActiveX вызывается таким образом:
var req = new ActiveXObject("Microsoft.XMLHTTP");

В Mozilla а также Safari это делается проще (этак как будто затем это объект, встроенный в JavaScript):
var req = new XMLHttpRequest();

Разумеется из-за таких различий вам должен быть создавать в коде ветки, каждая из которых станет выполняться в зависимости от того, в каком браузере загружен скрипт. Существует немножко способов, как будто сваять это (включая различные мудрёные хаки а также метод "условных комментариев"). Но я считаю, что именно лучше всего просто проверять в коде, поддерживается ли браузером тот или другой объект. Хорошим примером вероятно прислуживать код, взятый вместе с сайта Apple, в каком месте выложена документация ровно по этому объекту. Давайте им а также будем использовать:
var req;

function loadXMLDoc(url)
// branch for native XMLHttpRequest object
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send(null);
// branch for IE/Windows ActiveX version

req = new XMLHttpRequest();
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send(null);
// branch for IE/Windows ActiveX version
else if (window.ActiveXObject)
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req) {
req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send();

req.onreadystatechange = processReqChange;
req.open("GET", url, true);
req.send();

}
}

В этом коде особенно гордо обратить интерес на свойство onreadystatechange. Посмотрите, как будто ему присваивается значение функции processReqChange. Это свойство - хендлер события, которое запускается всякий момент, в какое время меняется состояние объекта req. Состояния обозначаются номерами вместе с 0 (объект неинициализирован) согласно 4 (запрос выполнен). Важно это благодаря тому что, что именно наш скрипт отнюдь не станет дожидаться ответа от сервера, дабы продолжить свою работу. HTTP-запрос станет сформирован а также отослан на сервер, однако скрипт станет выполняться далее. Из-за того, что сейчас все мы выбрали этакий вариация поведения, нам воспрещено просто в конце функции отдать итог запроса, этак как будто нам неизвестно, получили все мы его к этому времени или конечно нет. С целью сего все мы а также предусмотрели функцию processReqChange, которая станет отслеживать состояние объекта req, а также сообщит нам в нужное время, что именно процесс получения документа закончен, а также все мы можем двигаться далее.

Для сего функции processReqChange требуется проверять две вещи. Первая - дожидаться, в какое время состояние объекта req изменится на 4 (означающее, что сейчас процесс получения документа вместе с сервера закончен). Второе, это проверить HTTP-статус ответа. Вы знаете, что именно код 404 означает "файл никак не найден" а также 500 - "произошла ошибка на сервере". Но нам нужен древний добродушный код 200 ("все ОК"), какой означает, что сейчас на сервере наш запрос был успешно выполнен. Если бы все мы получили а также состояние 4 а также код 200, все мы можем продолжать выполнение нашего скрипта а также обрабатывать результаты, полученные от сервера. Разумеется в противном случае все мы имеете право обработать все ошибки, в частности, в случае если код ответа отличается от 200.
function processReqChange()

// only if req shows "complete"
if (req.readyState == {44)
// only if "OK"
if (req.status == 200) {
// ...processing statements go here...

// ...processing statements go here...
else
alert("There was a problem retrieving
the XML data:\n" + req.statusText);

}
}
На практике

Я собираюсь создать работающий пример с целью демонстрации вышеизложенных идей. Во многих веб-приложениях существует процедура, в какое время новый пользователь регистрируется на сервере а также требуется выбрать "ник" с целью регистрации. Очень зачастую оныйа#однако "ник" вынужден быть непревзойденным, а также потому что затем того, как будто пользователь выбрал себе "ник", на сервере осуществляется проверка ровно по базе данных пользователей, существует еще подобный "ник" или нет конечно. В случае вы в какое время-или регистрировались на каком-нибудь почтовом веб-сервере, вы помните, как будто утомительно подыскивать "ник", которым уже ни один человек далеко не пользуется. Было бы очень неплохо, в случае если бы проверка осуществлялась помимо необходимости всякий момент обновлять страницу.

Для решения все мы воспользуемся четырьмя ключевыми частями: XHTML-формой, функцией JavaScript, специально написанной с целью этой ситуации, двумя нашими общими функциями, О которых все мы говорили выше, а также в конце концов серверным скриптом, какой станет обращаться к базе данных.
Форма

Это самая легкая частица работы - простая вид вместе с полем с целью ввода "ника". К событию onblur все мы привязываем наш скрипт проверки. С целью того, для того чтобы вывести пользователю сообщение об результатах проверки, я вставил его в форму а также спрятал вместе с помощью CSS. Это не менее элегантный а также обходительный средство, чем стандартное диалоговое окно функции alert().
onblur="checkName(this.value,'')" />

В CSS объявлены параметры класса hidden, однако схоже уже одного класса error, какой служит с целью вывода сообщений об ошибке.
span.hidden
display: none;

span.error
display: inline;
color: black;
background-color: pink;

Обработка введенных данных

Функция checkName служит с целью проверки данных, введенных пользователем форму. Задача функции - взять данные, найти решение, какому серверному скрипту данные данные отдать, вызвать другую функцию, которая сделает всю "грязную" работу вместе с HTTP-запросами а также ответами, а также дальше обработать ответ. Эта наша функция станет состоять из двух элементов. Одна частица - берет данные из формы, только другая - обрабатывает ответ от сервера. Я объясню, к чему это сделано, еле-еле позднее.
function checkName(input, response)

if (response != ''){
// Response mode
message = document.getElementById('nameCheckFailed');
if (response == '1'){
message.className = 'error';

// Response mode
message = document.getElementById('nameCheckFailed');
if (response == '1'){
message.className = 'error';

message.className = 'error';
else
message.className = 'hidden';

}else
// Input mode
url = 'http://localhost/xml/checkUserName.php?q=' \\
+ input;
loadXMLDoc(url);

}

Ответ обрабатывается просто - ответ, какой все мы получим от серверного скрипта, станет или 1, или 0. 1 означает, что сейчас этакий "ник" еще кем-так применяется. В зависимости от ответа наша функция обновляет название класса сообщения об ошибке - оно или показывается, или прячется. Как понятно из кода, работу на сервере выполняет скрипт checkUserName.php.
Формирование HTTP-запроса а также ответа

Как вы наблюдали выше, занятие вместе с HTTP выполняется двумя функциями: loadXMLDoc а также processReqChange. В первом почти что ничто менять никак не надобно, но в втором требуется кое-что именно поменять с целью работы вместе с DOM-ом.

Как вы помните, пока что успешный итог выполнения запроса далеко не станет передан функции processReqChange, все мы отнюдь не можем из этой функции отдать какое-или значение. Из-за сего нам требуется выполнять очевидный вызов функции из другого места кода, для того чтобы воспользоваться результатом. Вот отчего функция checkName разбита на две элементы. Таким образом, главная задача функции processReqChange состоит в том, дабы обработать XML-ответ, полученный от сервера, а также передать определенное значение из сего ответа функции checkName.

Мы никак не хотим добавить в данные функции каковой-или неприятный код, таким образом как будто данные функции могут использоваться а также другими частями страницы с целью обращения к серверу. Поэтому все мы а также отнюдь не вписывали в функцию processReqChange название функции checkName. Вместо сего все мы решили, что именно сервер самолично станет в своем ответе отдавать название функции, которая к нему обращалась.
standalone="yes"?>

checkName

1

Разбор сего простого ответа выполняется но без каких-или проблем.
function processReqChange()

// only if req shows "complete"
if (req.readyState == {44)
// only if "OK"
if (req.status == 200) {
// ...processing statements go here...
response = req.responseXML.documentElement;

method = response.getElementsByTagName('method') \\
[0].firstChild.data;

result = response.getElementsByTagName('result') \\
[0].firstChild.data;

eval(method + '(\'\', result)');

// ...processing statements go here...
response = req.responseXML.documentElement;

method = response.getElementsByTagName('method') \\
[0].firstChild.data;

result = response.getElementsByTagName('result') \\
[0].firstChild.data;

eval(method + '(\'\', result)');
else
alert("There was a problem retrieving \\
the XML data:\n" + req.statusText);

}
}

Обратившись к свойству responseXML объекта XMLHttpRequest, все мы получаем XML-ответ, пришедший от сервера, кой все мы далее разбираем вместе с помощью DOM. Взяв из ответа название функции, которая требовала сейа#только ответ, все мы знаем, каковой функции надобно передать полученное значение. После того, как будто вы закончите тестирование, уберите условие else, дабы скрипт отнюдь не тормошил пользователей лишним сообщением об ошибке.
Серверный скрипт

Последний элемент нашей мозаики - это серверный скрипт, кой станет приобретать запрос, обрабатывать его а также отдавать ответ в виде XML. В нашем примере скрипт станет обращаться к базе данных пользователей, дабы определить, применяется ли еще настоящий "ник" или конечно нет. Ради краткости в моем примере скрипт никак не использует базу данных, но просто проверяет 2-ва имени "Drew" а также "Fred".
header('Content-Type: text/xml');

function nameInUse($q)

if (isset($q)){
switch(strtolower($q))
{
case 'drew' :
return '1';
break;
case 'fred' :
return '1';
break;
default:
return '0';

switch(strtolower($q))
{
case 'drew' :
return '1';
break;
case 'fred' :
return '1';
break;
default:
return '0';

case 'drew' :
return '1';
break;
case 'fred' :
return '1';
break;
default:
return '0';

}else
return '0';

}
?>

standalone="yes"?>'; ?>

checkName
echo nameInUse($_GET['q']) ?>


Разумеется, ту же процедуру проверки надобно предусмотреть а также в том серверном скрипте, какой станет выполняться, в какое время пользователь нажмет кнопку "Submit" на форме регистрации. Это на тот приключение, в случае около него в браузере был отключен JavaScript, или пользователь намеренно ввел "ник", какой еще применяется. Кроме того на загруженных сайтах вероятно этак случиться, что именно в время выбора "ника" он был свободен, но на момент подачи его уж кто-так занял.

В качестве следующего шага расширьте сами функциональность скрипта. Например сервер вероятно отдавать варианты альтернативных "ников" на основе "ника", выбранного пользователем, а еще занятого.
В заключение

Этот совсем небольшой пример как только слегка касается темы приминения объекта XMLHttpRequest. Вот как только отдельные примеры его приминения: Google Suggest, в каком месте XMLHttpRequest применяется ради того, для того чтобы подсказать искомые слова, приложение Ta-da Lists, в каком месте данные подаются на сервере опять-таки вместе с помощью XMLHttpRequest благодаря чему интерфейс работает очень резво. Самое интересное на этом месте отнюдь не том, затем чтобы заставить код трудиться, однако в том, дабы разыскать еще раз какие-или лучшие способы его приминения.

Навигация

Консультации менеджера on-line.
phones.hot-price.ru