Недоліком об'єкта XMLHttpRequest є відсутність можливості ограні_ чить час очікування виконання запиту. Цей недолік особливо критичний для синхронних запитів. Якщо зв'язок з сервером пропаде, веб_броузер окажет_ ся заблокованим в методі send () і не буде реагувати на дії пользо_ Ватель. У разі асинхронних запитів такого не відбувається, оскільки метод send () не блокується, і веб_броузер може продовжувати реагувати на дії користувача. Однак і тут існує проблема обмеження часу випол_ нання запиту. Припустимо, що додаток за допомогою об'єкта XMLHttpRe_ quest запустило HTTP_запрос, коли користувач клацнув на кнопці. Щоб запобігти можливості відправки кількох запитів, не зайве зробити кнопку неактивній до того моменту, як прибуде відповідь сервера. Але що якщо сервер зупиниться або станеться щось, що перешкодить отриманню відповіді на за_ прос? Браузер не буде заблокований, але можливості програми із_за неак_ тивной кнопки виявляться обмеженими.
Щоб уникнути атак, було б зручно мати можливість ус_ новлюють власні тайм_аути за допомогою функції Windows.setTimeout () при виконанні HTTP_запросов. У звичайній ситуації відповідь приходить до того, як буде викликаний оброблювач події таймера, - в цьому випадку можна просто викликати функцію Window.clearTimeout (), щоб скасувати спрацьовування таймера. З іншого боку, якщо обробник події від таймера буде викликаний раніше,
508 Глава 20. Робота з протоколом HTTP
ніж властивість readyState отримає значення 4, виконання запиту можна буде от_ нити за допомогою методу XMLHttpRequest.abort (). Після цього звичайно треба із_ вестися користувача про те, що спроба виконання запиту зазнала неуда_ чу (наприклад, методом Window.alert ()). Якщо в цьому гіпотетичному прикладі пе_ ред запуском запиту кнопка була деактивовано, її можна буде повторно ак_ тівіровать після закінчення граничного часу очікування.
У прикладі 20.7 визначається функція HTTP.get (), яка демонструє тільки що описаний прийом організації тайм_аута. Вона являє собою усовер_ шенствованную версію функції HTTP.getText () з прикладу 20.2 і підтримує багато з можливостей, що демонструвалися в попередніх прикладах, вклю_ чаю обробку помилок, параметри запиту та метод HTTP._getResponse (), опісан_ ний вище. Крім того, вона допускає можливість вказати необов'язкову функцію зворотного виклику, яка буде викликатися щоразу, коли про_ зійде подія onreadystatechange зі значенням властивості readyState, відмінним від 4. У таких браузерах, як Firefox, обробник цієї події може визивать_ ся неодноразово зі значенням 3, і дана функція зворотного виклику дозволяє сценарієм демонструвати користувачеві індикатор процесу завантаження.
Приклад 20.7. Допоміжна функція HTTP.get ()
* Відправляє HTTP_запрос GET із заданим URL. У разі успішного
* Отримання відповіді він перетворюється в об'єкт на основі заголовка
* Content_Type і передається зазначеної функції зворотного виклику.
* Додаткові аргументи можуть бути передані у вигляді властивостей об'єкта options.
* Якщо отримана відповідь з повідомленням про помилку (наприклад, повідомлення
* 404 Not Found), код стану та повідомлення передаються функції
* Options.errorHandler. Якщо обробник помилок не визначений, викликається
* Функція зворотного виклику зі значенням null в аргументі.
* Якщо об'єкт options.parameters визначено, його властивості інтерпретуються
* Як імена та значення параметрів запиту. За допомогою HTTP.encodeFormData ()
* Вони перетворюються в рядок, яку можна вставити в URL, після чого ця
* Рядок додається в кінець URL слідом за символом '?'.
* Якщо визначена функція options.progressHandler, вона буде викликатися
* Щоразу, коли властивість readyState знаходить нове значення, менше 4.
* Кожен раз цієї функції буде передаватися кількість викликів цієї функції.
* Якщо вказано значення options.timeout, робота об'єкта XMLHttpRequest буде
* Перервана, якщо клопотання не буде виконаний до закінчення заданого числа мілісекунд.
* Якщо граничний час очікування минув і визначена функція
* Options.timeoutHandler, вона буде викликана з рядком
* URL запиту у вигляді аргументу.
HTTP.get = function (url, callback, options)
var n = 0; var timer;