Íåìíîãî îá AJAX
Àâòîð: Àðòåìüåâ Ñåðãåé Èãîðåâè÷ ICQ: 438856621 email: _spin_@bk.ru |
Ajax (÷èòàåòñÿ êàê «àÿêñ» èëè "àäæàêñ") – ýòî ýâîëþöèÿ JS. Îáû÷íûå ñêðèïòû JS, êîòîðûå ìû èñïîëüçîâàëè â ïðèìåðàõ, íà÷èíàþò ñâîþ ðàáîòó ñ çàãðóçêè ñòðàíèöû è çàêàí÷èâàþò ïðè åå çàêðûòèè (èëè ðàíüøå, åñëè âûïîëíèëèñü ïîëíîñòüþ). Îáíîâëåíèå ñòðàíèöû (ïî êíîïêå «îáíîâèòü») áðàóçåðà ðàâíîñèëüíî åå çàêðûòèþ è ïîñëåäóþùåìó îòêðûòèþ, à ýòî çíà÷èò, ÷òî ñêðèïò áóäåò îïÿòü âûïîëíÿòüñÿ ñ ñàìîãî íà÷àëà. Íàïðèìåð:
<script type="text/javascript" language="javascript"> var myCounter = 0 function runMultiple() { var cntDiv = document.getElementById("counter"); if(cntDiv) { cntDiv.innerHTML = myCounter; cntDiv.style.backgroundColor = '#' + (myCounter + 100) * 1234; myCounter++; } } var timerMulti = window.setInterval("runMultiple();", 1000); </script> ... <div id="counter" style="border:1px dotted blue; top:100px;left:100px;position:absolute; width:50px;height:20px;text-align:center;"> 0 </div>
Êàê âèäèòå, ïðè îáíîâëåíèè ñòðàíèöû ñ÷åò÷èê âñåãäà ñáðàñûâàåòñÿ â èñõîäíîå çíà÷åíèå.
Èíîãäà òàêîå âûïîëíåíèå áûâàåò î÷åíü íåóäîáíûì. Ïðåäñòàâüòå, ÷òî âû çàãðóçèëè ôîòîãàëåðåþ ôîòîãðàôèé âûñîêîãî ðàçðåøåíèÿ (à çíà÷èò è áîëüøîãî ðàçìåðà). Îäíà èç íèõ âàì ïîíðàâèëàñü, è âû ðåøèëè ïîñòàâèòü åé îöåíêó «îòëè÷íî». Âûáèðàåòå íóæíóþ îöåíêó è æìåòå íà êíîïêó «Îöåíèòü». Áðàóçåð ïîøë¸ò îöåíêó íà ñåðâåð, êîòîðûé çàíåñ¸ò å¸ â áàçó è âåðí¸ò áðàóçåðó ïåðåñ÷èòàííóþ ñðåäíþþ îöåíêó. Íî ÷òîáû îòîáðàçèòü åå , áðàóçåð ïåðåçàãðóçèò âñþ ñòðàíèöó (îáíîâèò å¸). Åñòåñòâåííî áóäóò ïåðåçàãðóæåíû è âñå êàðòèíêè, à ýòî ëèøíèé òðàôèê è âðåìÿ îæèäàíèÿ.
Ðàññìîòðåííûé ïðèìåð íàçûâàåòñÿ ñèíõðîííûì âûïîëíåíèåì, ò.å. ñêðèïò âûïîëíÿåòñÿ ñèíõðîííî ñ äîêóìåíòîì. Òåõíîëîãèÿ AJAX (ðàñøèôðîâûâàåòñÿ êàê "Àñèíõðîííûé JavaScript") ïîçâîëÿåò ñêðèïòó ðàáîòàòü êàê-áû íåçàâèñèìî îò îñíîâíîé ñòðàíèöû. Ïî÷åìó "êàê-áû" âû ïîéìåòå ïîñëå èçó÷åíèÿ äàííîãî óðîêà.
Âíóòðåííåå óñòðîéñòâî Ajax äîñòàòî÷íî ñëîæíîå è ïîíèìàíèå åãî òðåáóåò îò ïðîãðàììèñòà õîðîøèõ ãëóáîêèõ çíàíèé. Ìû íå áóäåì âäàâàòüñÿ â äåáðè ïðîòîêîëîâ, à âîñïîëüçóåìñÿ ãîòîâîé áèáëèîòåêîé, íàïðèìåð JsHTTPRequest. Ýòà áèáëèîòåêà ïðåäîñòàâëÿåò ïðîñòîé è ïîíÿòíûé ìåõàíèçì èñïîëüçîâàíèÿ Ajax äëÿ ïðîãðàììèñòîâ äàæå ñ íåáîëüøèì îïûòîì.
Äëÿ íà÷àëà ðàáîòû íàäî ñêà÷àòü áèáëèîòåêó, íàïðèìåð îòñþäà. Êðîìå òîãî, íàì ïîíàäîáèòñÿ ñåðâåð, ãäå ìû áóäåì ðàçìåùàòü ñåðâåðíóþ ÷àñòü Ajax. Ñåðâåðíàÿ ÷àñòü â äàííîì ñëó÷àå ñîñòîèò èç íåñêîëüêèõ ñêðèïòîâ íà ÿçûêå PHP ( ôàéëîâ áèáëèîòåêè JsHTTPRequest è ôàéëà íàøåãî ñêðèïòà îáíîâëåíèÿ îöåíîê).  êà÷åñòâå ñåðâåðà ìîæíî âçÿòü Denver, ZendCore èëè ÷òî-òî ïîäîáíîå.
Èòàê, èçìåíèì ïðåäûäóùèé ïðèìåð òàêèì îáðàçîì, ÷òîáû ñ÷åò÷èê íå ñáðàñûâàëñÿ ïðè ïîñûëêå äàííûõ íà ñåðâåð.
Ñêðèïò ñ÷¸ò÷èêà îñòà¸òñÿ ïðåæíèì:
<script type="text/javascript" language="javascript"> var myCounter = 0 function runMultiple() { var cntDiv = document.getElementById("counter"); if(cntDiv) { cntDiv.innerHTML = myCounter; cntDiv.style.backgroundColor = '#' + (myCounter + 100) * 1234; myCounter++; } } var timerMulti = window.setInterval("runMultiple();", 1000); </script>
Äîáàâèì ïîäêëþ÷åíèå áèáëèîòåêè JsHTTPRequest è ñïåöèàëüíûé ìåòîä äëÿ îáðàáîòêè êëèêà íà êíîïêå îöåíêè:
// ïîäêëþ÷àåì ôàéë áèáëèîòåêè <script src="JsHttpRequest.js"></script> <script type="text/javascript" language="JavaScript"> function doLoad(value) { // Ñîçäà¸ì íîâûé îáúåêò JsHttpRequest var req = new JsHttpRequest(); // Îïðåäåëÿåì êîä ôóíêöèè, êîòîðûé áóäåò // àâòîìàòè÷åñêè âûçâàí ïî îêîí÷àíèè // çàïðîñà ê ñåðâåðó req.onreadystatechange = function() { if (req.readyState == 4) { // Çàïèñûâàåì ðåçóëüòàòû â ñîîòâåòñòâóþùèé áëîê document.getElementById('result').innerHTML = '<b>Îöåíêà ïîëüçîâàòåëÿ: ' + req.responseJS.usrMark+ '<br> ' + '<b>Íîâàÿ ñðåäíÿÿ îöåíêà: ' + req.responseJS.avgMark+ '<br> '; // Âûâîäèì âîçìîæíûå îøèáêè è îòëàäî÷íóþ èíôó document.getElementById('debug').innerHTML = req.responseText; } } // Ãîòîâèì ïîäêëþ÷åíèå ê ñåðâåðíîé ÷àñòè req.open(null, 'smpl_backend.php', true); // Ïîñûëàåì äàííûå íà ñåðâåð req.send( { mark: value } ); } </script>
Îñòàëîñü äîáàâèòü íåìíîãî HTML-êîäà äëÿ êíîïêè è ðàçìåùåíèÿ ðåçóëüòàòîâ:
<form> Âàøà îöåíêà: <input type="text" name="text" /> <input type="button" value="Îöåíèòü" onclick="doLoad(this.form.text.value)" /> </form> <div id="result" style="border:1px solid #000; padding:2px"> Áëîê ðåçóëüòàòîâ </div> <div id="debug" style="border:1px dashed red; padding:2px"> Áëîê îøèáîê è îòëàäî÷íîé èíôîðìàöèè </div>
Ýòîò ñêðèïò ðàáîòàåò ñëåäóþùèì îáðàçîì: ïðè íàæàòèè íà êíîïêó «îòïðàâèòü» âûçûâàåòñÿ ìåòîä îáúåêòà JsHTTPRequest, ñ ïàðàìåòðîì â âèäå ìàññèâà çíà÷åíèé. Ìàññèâ ìîæåò èìåòü ëþáîé ôîðìàò è ñîäåðæàòü ïðàêòè÷åñêè ëþáûå äàííûå. Îäíîâðåìåííî ñ ýòèì ìû îïèñûâàåì òàê íàçûâàåìóþ «callback» ôóíêöèþ. Ýòà ôóíêöèÿ (ôóíêöèÿ îáðàòíîãî âûçîâà onreadystatechange) áóäåò âûçâàíà, êîãäà áóäåò ïîëó÷åí îòâåò îò ñåðâåðà è íàäî áóäåò îáðàáîòàòü ðåçóëüòàòû. Íàøà ôóíêöèÿ ïðîñòî îòîáðàæàåò ðåçóëüòàòû çàïðîñà â ñîîòâåòñòâóþùèõ áëîêàõ.
 îáùåì âèäå âûïîëíåíèå Ajax ïðîèñõîäèò â 3 ýòàïà:
- Ïîäãîòîâêà äàííûõ è èíòåðôåéñà (íàïðèìåð, áëîêèðîâêà ïîëåé ââîäà è îòîáðàæåíèå êàðòèíêè ñ áåãóùåé ñòðîêîé èëè ÷àñàìè);
- Ïåðåäà÷à äàííûõ è îæèäàíèå ðåçóëüòàòà;
- Îáðàáîòêà ïîëó÷åííûõ ðåçóëüòàòîâ ñ ïîìîùüþ ôóíêöèè îáðàòíîãî âûçîâà (íàïðèìåð, ñêðûòèå êàðòèíêè îæèäàíèÿ, îòîáðàæåíèå ðåçóëüòàòîâ è îøèáîê, ðàçáëîêèðîâêà ïîëåé ââîäà).
Òåïåðü ðàññìîòðèì ñåðâåðíóþ ÷àñòü:
<?php // ïîäêëþ÷àåì AJAX-îáúåêò require_once "JsHttpRequest.php"; // Ñîçäà¸ì ýêçåìïëÿð AJAX-îáúåêòà è // îáÿçàòåëüíî óêàçûâàåì êîäîâóþ ñòðàíèöó $JsHttpRequest =& new JsHttpRequest("windows-1251"); // Ïîëó÷àåì äàííûå, ïåðåäàííûå áðàóçåðîì ïîëüçîâàòåëÿ $userMark = @$_REQUEST['mark']; $averageMark = $userMark + rand(1, 10); // ñîõðàíÿåì ðåçóëüòàòû â âûõîäíîé ìàññèâ $GLOBALS['_RESULT'] = array( "usrMark" => $userMark, "avgMark" => $averageMark ); ?>
 äàííîì ñëó÷àå ìû íå ó÷èòûâàåì ïðåäûäóùèå îöåíêè, à äëÿ ïðèìåðà ìåíÿåì îöåíêó ïîëüçîâàòåëÿ íà ñëó÷àéíóþ âåëè÷èíó â äèàïàçîíå îò 1 äî 10.
Êàê âèäèòå, èñïîëüçîâàòü Ajax äîâîëüíî íåñëîæíî. Ãëàâíîå ïðàâèëüíî îïèñûâàòü ïåðåäàâàåìûå è âîçâðàùàåìûå ïàðàìåòðû, à òàêæå ïîñòîÿííî ïîìíèòü, ÷òî ñêðèïò âûïîëíÿåòñÿ àñèíõðîííî, à çíà÷èò íàäî ïðåäóïðåæäàòü ïîëüçîâàòåëÿ î íåîáõîäèìîñòè ïîäîæäàòü. Íî èíîãäà áûâàþò ñèòóàöèè, êîãäà ïîëó÷èòü îòâåò ñòàíîâèòñÿ íåâîçìîæíî (ðàçðûâ ñîåäèíåíèÿ, îòêëþ÷åíèå ñåðâåðà èëè îòêàç â îáñëóæèâàíèè èç-çà ïåðåãðóçêè).  ýòîì ñëó÷àå íà ïîìîùü ïðèä¸ò ñïåöèàëüíûé òàéìåð, êîòîðûé âçâîäèòñÿ â ìîìåíò îòïðàâêè äàííûõ íà ñåðâåð. Ýòîò òàéìåð ñðàáàòûâàåò ÷åðåç çàäàííûé ðàçðàáîò÷èêîì ïðîìåæóòîê âðåìåíè (íàïðèìåð, 30 ñåêóíä), ñîîáùàåò ïîëüçîâàòåëþ îá îøèáêå, ðàçáëîêèðóåò êíîïêè è ïîëÿ ââîäà, à òàê æå ìîæåò ïîïðîñèòü ïîëüçîâàòåëÿ ïîâòîðèòü ïîïûòêó ïîçæå.
Èñïîëüçîâàíèå Ajax äàåò ðàçðàáîò÷èêó ìàññó ïîëåçíûõ è ýôôåêòèâíûõ ñïîñîáîâ ïîñòðîåíèÿ èíòåðôåéñà ñòðàíèöû. Îïûòíûé ïðîãðàììèñò ìîæåò ñîçäàòü âåá-ñòðàíèöó, ìàëî îòëè÷àþùóþñÿ ïî âíåøíåìó âèäó è ôóíêöèîíàëüíîñòè îò îáû÷íîãî ïðèëîæåíèÿ. ßðêèé ïðèìåð – ñåðâèñ gmail, ëþáèìûé ìíîãèìè ïîëüçîâàòåëÿìè çà ïðîñòîòó è óäîáñòâî.