AJAX (Asynchronous JavaScript and XML) - термин, который не так давно вошел в лексикон создателей WEB-приложений. Он означает целую совокупность технологий, объединяемых в рамках одного интерфейса и позволяющих отправлять запросы без перезагрузки страницы.
В этой статье мы рассмотрим одну из составляющих AJAX-приложений, а именно JavaScript-объект, генерирующий запросы. Вникать в принцип его работы необязательно, достаточно скопировать код в отдельный файл и при необходимости использовать. Для тех кто решил разобраться в работе самого объекта оставлены некоторые комментарии в коде.
AJAX-объект
// Базовый объект var net = new Object(); // Состояния запроса net.READY_STATE_UNINITIALIZED = 0; net.READY_STATE_LOADING = 1; net.READY_STATE_LOADED = 2; net.READY_STATE_INTERACTIVE = 3; net.READY_STATE_COMPLETE = 4; // Конструктор // key - Ключ запроса в массиве requestsHash // method - метод отправки запроса (POST, GET) // url - URL скрипта на сервере, который обработает запрос // params - параметры запроса (test=1&flag=2) // onload - callback-функция, обработчик после загрузки // onerror - callback-функция, обработчик в случае ошибки // contentType - тип контента запроса (text/html) // headers - прочие заголовки, кроме content-type, например, Expires net.ContentLoader = function(key, method, url, params, onload, onerror, contentType, headers) { this.hashKey = key; // Свойство для рапознавания браузеров, не поддерживающих request this.unrequestBrowser = false; // request - объект this.req = null; this.onload = onload; // Если её нет, вызывается дефолтный обработчик this.onerror = (onerror) ? onerror : this.defaultError; // Вызываем метод для генерации запроса this.loadXMLDoc(method, url, params, contentType, headers); } // Все методы записаны в прототип net.ContentLoader.prototype = { // Methods // loadXMLDoc - метод, для генерации request-запроса loadXMLDoc : function(method, url, params, contentType, headers) { if (!method) method="GET"; if (!contentType && method=="POST") contentType='application/x-www-form-urlencoded'; if (window.XMLHttpRequest) { this.req=new XMLHttpRequest(); } else if (window.ActiveXObject) { this.req=new ActiveXObject("Microsoft.XMLHTTP"); } else { this.unrequestBrowser = true; return; } if (this.req) { try { this.req.open(method,url,true); if (contentType){ this.req.setRequestHeader('Content-Type', contentType); } if (headers) { for (var h in headers) { this.req.setRequestHeader(h,headers[h]); } } var loader=this; this.req.onreadystatechange=function() { loader.onReadyState.call(loader); } this.req.send(params); } catch (err){ this.onerror.call(this); } } }, // onReadyState - метод для обработки ответов сервера onReadyState : function() { var req=this.req; var ready=req.readyState; if (ready==net.READY_STATE_COMPLETE) { var httpStatus=req.status; if (httpStatus==200 || httpStatus==0) { this.onload.call(this); } else { this.onerror.call(this); } } }, // defaultError - метод обработки ошибок по умолчанию defaultError : function() { alert("error fetching data!"+"\n\nreadyState:"+this.req.readyState +"\nstatus: "+this.req.status+"\nheaders: "+this.req.getAllResponseHeaders()); } } // Массив для хранения нескольких запросов var requestsHash = []; // Функция, создающая новый экземпляр объекта net.ContentLoader // Записывает запросы в requestsHash // Возвращает свойство unrequestBrowser function setAjaxRequest(method, url, params, onload, onerror, contentType, headers) { // Check of necessary parameters if (!url) { alert("Necessary parameters are not specified"); return; } requestsHash.push(new net.ContentLoader(requestsHash.length, method, url, params, onload, onerror, contentType, headers)); return requestsHash[requestsHash.length - 1].unrequestBrowser; }
Подготовка
Для создания так называемого асинхронного запроса и получения ответа потребуются некоторые условия:
1) Серверный скрипт, который примет запрос, обработает его и выдаст ответ. В качестве примера здесь будет использован PHP-скрипт http://fastcoder.org/demo/ajaxDemo.php, который на выходе отдает XML-дерево такого вида:
<xml> <result>Success!</result> <error></error> </xml> 2) Функция, которая отправит запрос. Она уже есть (setAjaxRequest) и встроена в приведенный выше AJAX-объект, ей и воспользуемся.
3) Функции-обработчики, которые примут ответ (или возможную ошибку) и надлежащим образом отреагируют. Они будут вызваны как callback-функции. Это значит что this для них вернет ссылку на экземпляр объекта net.ContentLoader.
// Функция обработки ответа function ansHandler() { // Для обработки ответа можно изпользовать два основных свойства request-объекта // responseText - вернет ответ в качестве текстовой переменной // responseXML - вернет XML-ответ // Последовательно воспользуемся обоими свойствами alert(this.req.responseText); // XML-структурой можно управлять более эффективно // Например, получать значения отдельных узлов var xml = this.req.responseXML.firstChild; if (xml.nodeType != 1) xml = xml.nextSibling; // fix for Opera var result = xml.getElementsByTagName("result")[0].firstChild.nodeValue; alert("result = " + result); } // Функция обработки ошибок function errorHandler() { alert("При обработке запроса произошла ошибка, повторите попытку снова"); }
Формирование и отправка запроса
function doit() { var method = "GET"; var url = "http://fastcoder.org/demo/ajaxDemo.php"; var params = false; // Без параметров var onload = ansHandler; var onerror = errorHandler; var contentType = headers = false; // Без заголовков return setAjaxRequest(method, url, params, onload, onerror, contentType, headers); }
И какой-нибудь HTML-элемент, например ссылку, для отправки запроса:
<a onclick="return doit();" href="#">Отправить запрос</a>
Замечания 1) Браузер Opera ниже версии 8.0 не поддерживает request. Собственно для них и создавалось свойство unrequestBrowser, которое возвращается всеми функциями. Если вернется true, то произойдет простой переход по ссылке. 2) Скрипт можно улучшить и расширить, но необходимый минимум (и даже больше) в этой статье имеется. Если вы нашли ошибки или пришли к выводу, что чего-то существенно не хватает - пишите.
Автор: Александр Бурцев
|