Увидев название, некоторые учащиеся могут подумать: «Я использовал
xhrуспешно разместил многоAjaxЯ просил, и я достаточно хорошо разбираюсь в его основных операциях. Я думал так же, как и вы, ребята, до недавнего времени я использовалxhrКогда я наступил на множество ям, я вдруг понял, что знаю недостаточно.xhr, я знаю только самое основное использование.
Поэтому я решил провести небольшое исследованиеxhrНо после прочтения многих блогов я не был удовлетворен, поэтому решил внимательно прочитать блог W3C.XMLHttpRequestстандарт. После прочтения стандарта я почувствовал себя просветленным, и я ощутил ясность, которой у меня никогда не было раньше. Эта статья является ссылкой на W3CXMLHttpRequestОн основан на стандарте и сочетается с некоторой практической проверкой.
Ajaxа такжеXMLHttpRequest
мы, как правилоAjaxЭквивалентноXMLHttpRequest, но при ближайшем рассмотрении оказывается, что это два понятия, принадлежащие к разным измерениям.
Вот что я считаю правильным
AjaxБолее точное объяснение: (взято изwhat is Ajax)
AJAX stands for Asynchronous JavaScript and XML. AJAX is a new technique for creating better, faster, and more interactive web applications with the help of XML, HTML, CSS, and Java Script.AJAX is based on the following open standards:
Browser-based presentation using HTML and Cascading Style Sheets (CSS).
Data is stored in XML format and fetched from the server.
Behind-the-scenes data fetches using XMLHttpRequest objects in the browser.
JavaScript to make everything happen.
Из приведенного выше пояснения можно узнать, что:ajaxявляется техническим решением, но неновая технология. он опирается на существующиеCSS/HTML/Javascript, а основная зависимость предоставляется браузеромXMLHttpRequestобъект, который позволяет браузеру испускатьHTTPзапросить и получитьHTTPотклик.
Итак, я резюмирую отношения между ними в одном предложении: мы используемXMLHttpRequestобъект для отправкиAjaxпросить.
XMLHttpRequestистория развития
XMLHttpRequestСначала это был просто интерфейс, предоставляемый браузером Microsoft. Позже его примеру последовали и основные браузеры, которые также предоставили этот интерфейс. Позднее W3C стандартизировал его и предложилXMLHttpRequestстандартный.XMLHttpRequestСтандарт делится наLevel 1а такжеLevel 2.XMLHttpRequest Level 1Основные недостатки заключаются в следующем:
-
В соответствии с политикой одного и того же источника отправка междоменных запросов невозможна;
-
Невозможно отправлять двоичные файлы (такие как изображения, видео, аудио и т. д.), только текстовые данные;
-
В процессе отправки и получения данных информация о ходе работы не может быть получена в режиме реального времени, и можно судить только о том, завершен ли он;
ТакLevel 2правильноLevel 1улучшен,XMLHttpRequest Level 2Были добавлены следующие функции:
-
Можно отправлять междоменные запросы, если это позволяет сервер;
-
Поддержка отправки и получения двоичных данных;
-
Добавлен объект formData для поддержки отправки данных формы;
-
При отправке и получении данных можно получить информацию о ходе выполнения;
-
Период ожидания запроса может быть установлен;
Конечно, для более подробного сравнения вы можете обратиться кЭта статья г-на Руана, в статье есть конкретные примеры кода для новых функций.
XMLHttpRequestсовместимость
оxhrсовместимость с браузером, вы можете напрямую просматривать результаты, предоставленные веб-сайтом «Могу ли я использовать»Совместимость XMLHttpRequest, скриншот приведен ниже.
Как видно из рисунка:
-
IE8/IE9, Opera Mini вообще не поддерживаются
xhrобъект -
IE10/IE11 частично поддерживается, не поддерживается
xhr.responseTypeдляjson -
Некоторые браузеры не поддерживают настройку таймаута запроса, то есть его нельзя использовать
xhr.timeout -
Некоторые браузеры не поддерживают
xhr.responseTypeдляblob
разрабатыватьXMLHttpRequestкак использовать
Давайте сначала посмотрим на использованиеXMLHttpRequestОтправитьAjaxПростой пример кода для запроса.
function sendAjax() {
//构造表单数据
var formData = new FormData();
formData.append('username', 'johndoe');
formData.append('id', 123456);
//创建xhr对象
var xhr = new XMLHttpRequest();
//设置xhr请求的超时时间
xhr.timeout = 3000;
//设置响应返回的数据格式
xhr.responseType = "text";
//创建一个 post 请求,采用异步
xhr.open('POST', '/server', true);
//注册相关事件回调处理函数
xhr.onload = function(e) {
if(this.status == 200||this.status == 304){
alert(this.responseText);
}
};
xhr.ontimeout = function(e) { ... };
xhr.onerror = function(e) { ... };
xhr.upload.onprogress = function(e) { ... };
//发送数据
xhr.send(formData);
}
Вышеупомянутое является использованиемxhrВ качестве примера отправки данных формы вы можете обратиться к комментариям для всего процесса.
Далее я буду стоять на точке зрения пользователя и представлю ее в форме вопроса.
xhrбазовое использование.
Я подробно расскажу о знаниях, связанных с каждым вопросом, и некоторые знания могут быть вами упущены.
Как установить заголовок запроса
отправкаAjaxпросьба (по существуHTTPrequest), нам может понадобиться установить некоторую информацию заголовка запроса, такую какcontent-type,connection,cookie,accept-xxxЖдать.xhrпри условииsetRequestHeaderчтобы мы могли изменить запрос
заголовок.
void setRequestHeader(DOMString header, DOMString value);
будь осторожен:
-
Заголовок первого параметра метода нечувствителен к регистру, то есть его можно записать в виде
content-type, что также можно записать какContent-Type, или даже пишется какcontent-Type; -
Content-TypeЗначение по умолчанию связано с конкретным типом отправляемых данных, см. раздел [Какие типы данных можно отправлять] этой статьи; -
setRequestHeaderДолжен бытьopen()После метода,send()Метод вызывается раньше, иначе будет выброшена ошибка; -
setRequestHeaderМожет вызываться несколько раз, конечное значение не будет перезаписаноoverrideспособ, но добавлениеappendПуть. Вот пример кода:
var client = new XMLHttpRequest();
client.open('GET', 'demo.cgi');
client.setRequestHeader('X-Test', 'one');
client.setRequestHeader('X-Test', 'two');
// 最终request header中"X-Test"为: one, two
client.send();
Как получить заголовок ответа
xhrДля получения заголовков ответов предусмотрено два метода:getAllResponseHeadersа такжеgetResponseHeader. Первый — получить все поля заголовка в ответе, а второй — получить значение указанного поля заголовка. Кроме того,getResponseHeader(header)изheaderАргументы не чувствительны к регистру.
DOMString getAllResponseHeaders();DOMString getResponseHeader(DOMString header);
Эти два метода кажутся простыми, но везде есть подводные камни.
Вы сталкивались с ямой внизу? - Во всяком случае, сталкивались. . .
-
использовать
getAllResponseHeaders()увидеть всеresponse headerс настоящей консольюNetworkвидел вresponse headerРазные -
использовать
getResponseHeader()получитьheaderзначение, браузер выдает ошибкуRefused to get unsafe header "XXX"
После некоторых поисков, наконецStack Overflow нашел ответ.
-
Причина 1:Ограничения сделаны в стандарте W3C xhr., который указывает, что клиент не может получить ответ в
Set-Cookie,Set-Cookie2Эти два поля, будь то однодоменный или междоменный запрос; -
Причина 2:Стандарт W3C cors также ограничивает междоменные запросы., который предусматривает, что для междоменных запросов поле заголовка ответа, которое может получить клиент, ограничено "
simple response header"а также"Access-Control-Expose-Headers(объяснение обоих терминов см. ниже).
"
simple response header"Включенные поля заголовка:Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma;
"Access-Control-Expose-Headers": Первое, на что следует обратить внимание, это"Access-Control-Expose-Headers"провестимеждоменный запросЭто поле в заголовке ответа, для запроса того же домена в заголовке ответа нет этого поля. указан в этом поле Поле заголовка — это поле, которое сервер разрешает показывать клиенту.
такgetAllResponseHeaders()получить толькоза пределы(то есть рассматривается какsafe) поля заголовка, а не всех полей; вместо этого вызовgetResponseHeader(header)метод,headerпараметр должен бытьза пределыполе заголовка, иначе вызов сообщитRefused to get unsafe headerошибка.
Как указатьxhr.responseтип данных
Иногда мы желаемxhr.responseВозвращается тип данных, который нам нужен. Например: данные, возвращаемые в ответе, представляют собой простую строку JSON, но мы ожидаем, чтоxhr.responseТо, что мы получаем, это объект js напрямую, как мы его реализуем?
Есть 2 способа добиться этого, один из нихlevel 1при условииoverrideMimeType()метод, другойlevel 2только при условииxhr.responseTypeАтрибуты.
xhr.overrideMimeType()
overrideMimeTypeдаxhr level 1Метод есть, так что совместимость браузера хорошая. Цель этого метода состоит в том, чтобы переопределитьresponseизcontent-type, какой смысл это делать? Например: сервер возвращает копию клиентуdocumentилиxmlдокументации, мы надеемся в конечном итоге пройтиxhr.responseесть одинDOMобъект, то вы можете использоватьxhr.overrideMimeType('text/xml; charset = utf-8')реализовать.
Чтобы дать другой сценарий использования, мы все знаемxhr level 1Прямая передача двоичных данных большого двоичного объекта не поддерживается, так что, если вы действительно хотите передать большой двоичный объект? использовалoverrideMimeTypeметод решения этой проблемы.
Вот пример кода для получения файла изображения:
var xhr = new XMLHttpRequest();
//向 server 端获取一张图片
xhr.open('GET', '/path/to/image.png', true);
// 这行是关键!
//将响应数据按照纯文本格式来解析,字符集替换为用户自己定义的字符集
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e) {
if (this.readyState == 4 && this.status == 200) {
//通过 responseText 来获取图片文件对应的二进制字符串
var binStr = this.responseText;
//然后自己再想方法将逐个字节还原为二进制数据
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
//String.fromCharCode(c & 0xff);
var byte = c & 0xff;
}
}
};
xhr.send();
в примере кодаxhrЗапрос на изображение, добавивresponseизcontent-typeИзмените на «text/plain; charset=x-user-defined», чтобыxhrПроанализируйте полученные данные большого двоичного объекта в текстовом формате, конечный пользовательthis.responseTextGOT - это двоичная строка, соответствующая файлу изображения, и, наконец, преобразует его в данные BLOB.
xhr.responseType
responseTypeдаxhr level 2Новый атрибут, указывающийxhr.responseТип данных, все еще есть некоторые проблемы с совместимостью, вы можете обратиться к [XMLHttpRequestСовместимость] в этом разделе. ТакresponseTypeКакие форматы можно задать?Я просто сделал таблицу следующим образом:
| стоимость | xhr.responseтип данных |
иллюстрировать |
|---|---|---|
"" |
Stringнить |
Значение по умолчанию (без установкиresponseTypeВремя) |
"text" |
Stringнить |
|
"document" |
Documentобъект |
надеюсь вернутьсяXMLиспользуется при форматировании данных |
"json" |
javascriptобъект |
Проблема совместимости, IE10/IE11 не поддерживает |
"blob" |
Blobобъект |
|
"arrayBuffer" |
ArrayBufferобъект |
Ниже приведен пример кода, который также получает изображение по сравнению сxhr.overrideMimeType,использоватьxhr.responseдобиться гораздо проще.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
//可以将`xhr.responseType`设置为`"blob"`也可以设置为`" arrayBuffer"`
//xhr.responseType = 'arrayBuffer';
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
...
}
};
xhr.send();
резюме
Хотя вxhr level 2, они сосуществуют. Но найти не сложно,xhr.responseTypeэто заменитьxhr.overrideMimeType()из,xhr.responseTypeнамного мощнее,xhr.overrideMimeType()сможет сделатьxhr.responseTypeможет сделать это. Таким образом, теперь мы можем полностью отказаться от использованияxhr.overrideMimeType().
Как получить данные ответа
xhrxhr.response,xhr.responseText,xhr.responseXML
-
xhr.response-
По умолчанию: пустая строка
"" -
Это свойство имеет правильное значение после завершения запроса.
-
Если запрос не завершен, значение этого свойства может быть
""илиnull, конкретно сxhr.responseTypeСвязанный: КогдаresponseTypeдля""или"text", значение"";responseTypeДля других значений значение равноnull
-
-
xhr.responseText-
По умолчанию пустая строка
"" -
только тогда, когда
responseTypeдля"text",""час,xhrЭто свойство доступно только для объекта и может быть вызвано только в данный момент.xhr.responseText, иначе выдать ошибку -
Правильное значение можно получить только при успешном выполнении запроса. В следующих двух случаях значение представляет собой пустую строку.
"": запрос не выполнен, запрос не выполнен
-
-
xhr.responseXML-
По умолчанию
null -
только тогда, когда
responseTypeдля"text","","document"час,xhrЭто свойство доступно только для объекта и может быть вызвано только в данный момент.xhr.responseXML, иначе выдать ошибку -
Правильное значение может быть получено только тогда, когда запрос выполнен успешно и возвращаемые данные верны. Следующие три случая являются значениями
null: когда запрос не выполнен, запрос завершается с ошибкой, запрос выполняется успешно, но возвращаемые данные не могут быть правильно проанализированы.
-
как отслеживатьajaxтекущее состояние заявки
размещение одногоajaxПосле запроса, что, если вы хотите отследить, в каком состоянии сейчас находится запрос?
использоватьxhr.readyStateЭто свойство можно проследить. Это свойство доступно только для чтения с 5 возможными значениями, соответствующимиxhrразные этапы. каждый разxhr.readyStateПри изменении значения срабатываетxhr.onreadystatechangeСобытия, мы можем сделать соответствующие государственные суждения в этом событии.
xhr.onreadystatechange = function () {
switch(xhr.readyState){
case 1://OPENED
//do something
break;
case 2://HEADERS_RECEIVED
//do something
break;
case 3://LOADING
//do something
break;
case 4://DONE
//do something
break;
}
| стоимость | условие | описывать |
|---|---|---|
0 |
UNSENT(исходное состояние, не открыто) |
В настоящее времяxhrобъект успешно построен,open()метод не вызывался |
1 |
OPENED(открыто, не отправлено) |
open()метод был вызван успешно,send()Метод еще не вызывался. Примечание: толькоxhrвOPENEDгосударство, чтобы позвонитьxhr.setRequestHeader()а такжеxhr.send(), иначе будет сообщено об ошибке |
2 |
HEADERS_RECEIVED(полученные заголовки ответов) |
send()Метод был вызван, заголовки ответа и статус ответа были возвращены |
3 |
LOADING(Скачивание тела ответа) |
тело ответа (response entity body) скачивается, в этом состоянии проходитxhr.responseвозможно, уже есть данные ответа |
4 |
DONE(Весь процесс передачи данных заканчивается) |
Весь процесс передачи данных завершается, независимо от того, был ли запрос выполнен успешно или нет. |
Как установить время ожидания запроса
Если запрос долгое время не был успешным, чтобы не занимать ресурсы сети попусту, мы вообще будем активно завершать запрос.XMLHttpRequestпри условииtimeoutсвойство, позволяющее установить тайм-аут для запроса.
xhr.timeout
Единица: миллисекунды миллисекунды
По умолчанию:0, т.е. не устанавливать тайм-аут
Многие студенты знают, что:запрос на запусксчитать, если большеtimeoutЕсли запрос времени не завершен (включая успех/неудачу), событие ontimeout будет инициировано для активного завершения запроса.
[Так когда же это будетзапрос на запуск? 】
——xhr.onloadstartКогда событие срабатывает, то есть вы вызываетеxhr.send()время метода.
потому чтоxhr.open()просто создает соединение, но фактически не запускает передачу данных, иxhr.send()Здесь начинается настоящий процесс передачи данных. только звониxhr.send(), вызоветxhr.onloadstart.
[Так когда же это будетконец запроса? 】
——xhr.loadendкогда событие срабатывает.
Кроме того, есть две ямы, которые требуют внимания:
-
допустимый
send()установить это позжеxhr.timeout, но начальной точкой синхронизации по-прежнему является вызовxhr.send()момент метода. -
когда
xhrдля одногоsyncПри синхронном запросеxhr.timeoutдолжен быть установлен на0, иначе будет выброшена ошибка. По этой причине см. раздел [Как отправить синхронный запрос] этой статьи.
Как отправить синхронный запрос
xhrПо умолчанию отправляются асинхронные запросы, но синхронные запросы также поддерживаются (конечно, этого следует избегать в реальной разработке). Является ли это асинхронным или синхронным запросом, определяетсяxhr.open()входящийasyncрешение по параметрам.
open(method, url [, async = true [, username = null [, password = null]]])
-
method: метод запроса, напримерGET/POST/HEADERд., этот параметр не чувствителен к регистру -
url: запрошенный адрес, который может быть относительным адресом, напримерexample.php,этоотносительноотносительно текущей страницыurlпуть; также может быть абсолютным адресом, напримерhttp://www.example.com/example.php -
async: значение по умолчаниюtrue, который является асинхронным запросом, еслиasync=false, это синхронный запрос
До того, как я серьёзно изучил стандарт xhr W3C, я всегда думал, что синхронный запрос и асинхронный запрос — это только разница между блокирующим и неблокирующим, а остальные триггеры событий и настройки параметров должны быть одинаковыми, оказывается, я ошибался.
Стандарт W3C xhr оopen()Метод имеет следующее описание:
Throws an "InvalidAccessError" exception if async is false, the JavaScript global environment is a document environment, and either the timeout attribute is not zero, the withCredentials attribute is true, or the responseType attribute is not the empty string.
Из предыдущего абзаца видно, что когдаxhrДля синхронных запросов применяются следующие ограничения:
-
xhr.timeoutдолжно быть0 -
xhr.withCredentialsдолжно бытьfalse -
xhr.responseTypeдолжно быть""(Обратите внимание"text"тоже нельзя)
Если какое-либо из вышеперечисленных ограничений не выполняется, будет выдано сообщение об ошибке, а для асинхронных запросов ограничений на настройку этих параметров нет.
Я уже говорил, что страница должна стараться избегать использованияsyncСинхронный запрос, почему?
Потому что мы не можем установить время ожидания запроса (xhr.timeoutдля0, то есть неограниченное время). Без ограничения тайм-аута возможно, что синхронный запрос был вpendingсостояние, сервер не возвращает ответ, поэтому вся страница будет постоянно заблокирована, не в состоянии реагировать на другие действия пользователя.
Кроме того, в стандарте не упоминается ограничение запуска событий во время синхронных запросов, но в реальной разработке я столкнулся с некоторыми событиями, которые должны запускаться, но не запускаться. Как в хроме, когдаxhrдля синхронного запроса, вxhr.readyStateЗависит от2стали3, не заводитсяonreadystatechangeмероприятие,xhr.upload.onprogressа такжеxhr.onprogressСобытие также не срабатывает.
Как получить ход загрузки и загрузки
При загрузке или загрузке относительно больших файлов общим требованием к продукту является отображение текущей загрузки и загрузки в режиме реального времени.
мы можем пройтиonprogressСобытие для отображения прогресса в реальном времени, по умолчанию это событие срабатывает каждые 50 мс. Следует отметить, что процесс загрузки и процесс загрузки запускают разные объекты.onprogressмероприятие:
-
Загрузка инициируется
xhr.uploadобъектonprogressмероприятие -
Загрузка инициируется
xhrобъектonprogressмероприятие
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
function updateProgress(event) {
if (event.lengthComputable) {
var completedPercent = event.loaded / event.total;
}
}
какой тип данных может быть отправлен
void send(data);
xhr.send(data)Данные параметров могут быть следующих типов:
-
ArrayBuffer -
Blob -
Document -
DOMString -
FormData -
null
Если это запрос GET/HEAD,send()Методы обычно не передают параметры или передаютnull. Но даже если вы передаете параметры, они в конечном итоге игнорируются,xhr.send(data)Данные будут установлены наnull.
xhr.send(data)Тип данных параметра данных повлияет на заголовок запроса.content-typeЗначение по умолчанию:
-
если
dataдаDocumentтипа, такжеHTML Documentвведите, затемcontent-typeПо умолчаниюtext/html;charset=UTF-8; иначеapplication/xml;charset=UTF-8; -
если
dataдаDOMStringТипы,content-typeПо умолчаниюtext/plain;charset=UTF-8; -
если
dataдаFormDataТипы,content-typeПо умолчаниюmultipart/form-data; boundary=[xxx] -
если
dataэто другой тип, он не будет установленcontent-typeзначение по умолчанию
Конечно это простоcontent-typeзначение по умолчанию, но если вы используетеxhr.setRequestHeader()установить вручнуюcontent-typeзначение, указанное выше значение по умолчанию будет переопределено.
Кроме того, следует отметить, что если вызов осуществляется в отключенном состоянииxhr.send(data)метод, он выдаст ошибку:Uncaught NetworkError: Failed to execute 'send' on 'XMLHttpRequest'. Как только программа выдает ошибку, она не может продолжать выполнять следующий код без перехвата, поэтому вызовитеxhr.send(data)метод, вы должны использоватьtry-catchОтловить ошибки.
try{
xhr.send(data)
}catch(e) {
//doSomething...
};
xhr.withCredentialsа такжеCORSкакие отношения
Все мы знаем, что при отправке одного и того же доменного запроса браузер
cookieавтоматически добавляется вrequest headerсередина. А вы когда-нибудь сталкивались с таким сценарием: при отправке междоменного запроса,cookieне добавляется автоматически вrequest headerсередина.
Причина этой проблемы:CORSВ стандарте оговорено, что по умолчанию браузеры не могут отправлять никакую аутентификационную информацию при отправке междоменных запросов (credentials)Такие как"cookies"а также"HTTP authentication schemes".пока неxhr.withCredentialsдляtrue(xhrОбъект имеет свойство, называемоеwithCredentials, значение по умолчаниюfalse).
Итак, первопричиной являетсяcookiesЭто также своего рода аутентификационная информация.clientнеобходимо установить вручнуюxhr.withCredentials=true,а такжеserverконец также должен позволятьrequestМожет нести аутентификационную информацию (т.response headerсодержитAccess-Control-Allow-Credentials:true), чтобы браузер автоматическиcookieДобавить вrequest headerсередина.
Кроме того, обратите особое внимание на один момент, когда-то междоменныйrequestможет нести аутентификационную информацию,serverКонец не должен бытьAccess-Control-Allow-OriginУстановить как*, но должно быть установлено на доменное имя запрашивающей страницы.
xhrСвязанные события
классификация событий
xhrСобытий так много, что иногда трудно вспомнить. Но когда я понимаю конкретную реализацию кода, это легко понять. НижеXMLHttpRequestЧасть кода реализации:
interface XMLHttpRequestEventTarget : EventTarget {
// event handlers
attribute EventHandler onloadstart;
attribute EventHandler onprogress;
attribute EventHandler onabort;
attribute EventHandler onerror;
attribute EventHandler onload;
attribute EventHandler ontimeout;
attribute EventHandler onloadend;
};
interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
};
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;
readonly attribute XMLHttpRequestUpload upload;
};
Из кода мы видим, что:
-
XMLHttpRequestEventTargetИнтерфейс определяет 7 событий:-
onloadstart -
onprogress -
onabort -
ontimeout -
onerror -
onload -
onloadend
-
-
Каждый
XMLHttpRequestEстьuploadсвойства, при этомuploadЯвляетсяXMLHttpRequestUploadобъект -
XMLHttpRequestа такжеXMLHttpRequestUploadунаследовал то же самоеXMLHttpRequestEventTargetинтерфейс, такxhrа такжеxhr.uploadВ первой статье перечислены 7 событий. -
onreadystatechangeдаXMLHttpRequestуникальное событие
Итак, с первого взгляда все ясно:xhrВсего 8 связанных событий: 7XMLHttpRequestEventTargetСобытие +1 уникальноеonreadystatechangeсобытие; иxhr.uploadтолько 7XMLHttpRequestEventTargetмероприятие.
триггер события
Ниже тот, который я сделал самxhrТаблица условий срабатывания связанных событий, наиболее примечательной из которых являетсяonerrorУсловие запуска события.
| мероприятие | Условия срабатывания |
|---|---|
onreadystatechange |
в любое времяxhr.readyStateСрабатывает при изменении; ноxhr.readyStateФей0значение становится0не срабатывает. |
onloadstart |
передачаxhr.send()Запускается сразу после метода, еслиxhr.send()Если не вызывается, это событие не будет запущено. |
onprogress |
xhr.upload.onprogressНа этапе загрузки (т.xhr.send()Позже,xhr.readystate=2до) триггер, триггер каждые 50 мс;xhr.onprogressНа этапе загрузки (т.xhr.readystate=3time) срабатывает раз в 50 мс. |
onload |
Запускается при успешном выполнении запроса, в это времяxhr.readystate=4 |
onloadend |
Запускается, когда запрос завершается (включая успех запроса и отказ запроса) |
onabort |
при звонкеxhr.abort()пост-триггер |
ontimeout |
xhr.timeoutНе равно 0, начиная с запросаonloadstartначать считать, когда прибудетxhr.timeoutЗапрос установленного времени еще не завершенonloadend, это событие срабатывает. |
onerror |
Во время запроса, еслиNetwork errorвызовет это событие (еслиNetwork error, загрузка еще не завершена, она сработает первойxhr.upload.onerror, запустить сноваxhr.onerror; если это произойдетNetwork error, загрузка завершена, она сработает толькоxhr.onerror).Уведомление, это событие будет инициировано только при возникновении исключения на уровне сети. Для исключений на уровне приложения, таких как возвращенный ответxhr.statusCodeда4xx, не принадлежитNetwork error, так что не сработаетonerrorсобытие, но вызоветonloadмероприятие. |
Последовательность запуска события
Когда с запросом все в порядке, соответствующая последовательность срабатывания события выглядит следующим образом:
-
вызывать
xhr.onreadystatechange(каждый раз послеreadyStateКогда он изменится, он сработает один раз) -
вызывать
xhr.onloadstart
//Начало фазы загрузки: -
вызывать
xhr.upload.onloadstart -
вызывать
xhr.upload.onprogress -
вызывать
xhr.upload.onload -
вызывать
xhr.upload.onloadend
//Загрузка завершена, и начинается фаза загрузки: -
вызывать
xhr.onprogress -
вызывать
xhr.onload -
вызывать
xhr.onloadend
происходитьabort/timeout/errorОбработка исключений
В процессе запроса может произойтиabort/timeout/errorэти 3 исключения. Затем, когда эти исключения происходят,xhrЧто будет сделано дальше? Дальнейшая обработка выглядит следующим образом:
-
как только это произойдет
abortилиtimeoutилиerrorИсключение, немедленно прервать текущий запрос -
Буду
readystateустановлен в4, и триггерыxhr.onreadystatechangeмероприятие -
Если фаза загрузки не завершена, последовательно запускаются следующие события:
-
xhr.upload.onprogress -
xhr.upload.[onabort或ontimeout或onerror] -
xhr.upload.onloadend
-
-
вызывать
xhr.onprogressмероприятие -
вызывать
xhr.[onabort或ontimeout或onerror]мероприятие -
вызывать
xhr.onloadendмероприятие
в которомxhrОбратный вызов успешно зарегистрирован в событии?
Из событий, описанных выше, можно узнать, что еслиxhrЕсли запрос выполнен успешно, он сработаетxhr.onreadystatechangeа такжеxhr.onloadдва события. Итак, в каком событии мы регистрируем обратный вызов успеха? я склоняюсь кxhr.onloadсобытие, потому чтоxhr.onreadystatechangeкаждый разxhr.readyStateбудет срабатывать при изменении вместоxhr.readyState=4срабатывает когда.
xhr.onload = function () {
//如果请求成功
if(xhr.status == 200){
//do successCallback
}
}
Приведенный выше пример кода является очень распространенным способом написания: сначала оценитеhttpЯвляется ли код состояния200, если это так, запрос считается успешным, и выполняется обратный вызов успеха. В таких суждениях есть подводные камни, например, при возвращенииhttpкод состояния не200, но201, запрос также выполнен успешно, но логика обратного вызова не выполняется. Следовательно, более надежным методом суждения должен быть: когдаhttpКод состояния2xxили304считается успешным.
xhr.onload = function () {
//如果请求成功
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
//do successCallback
}
}
Эпилог
Наконец-то закончил писать...
После прочтения этого длинного стандарта W3C xhr у меня глаза заплыли...
Надеюсь, это краткое изложение поможет тем, кто только начинаетXMLHttpRequestты.
Наконец, дайте несколько расширенных учебных материалов, если вы:
-
хочу действительно понять
XMLHttpRequest, самый надежный способ - посмотреть наСтандарт W3C xhr; -
Хотите научиться использовать код
XMLHttpRequestОтправить различные типы данных, вы можете обратиться кЭта статья на html5rocks -
хочу иметь приблизительное представление
XMLHttpRequestОсновное использование , вы можете обратиться кВведение в XMLHttpRequest MDN; -
хочу знать
XMLHttpRequestпроцесс разработки, вы можете обратиться кСтатья учителя Руана; -
хочу знать
AjaxДля основного введения вы можете обратиться кAJAX Tutorial; -
Если вы хотите узнать о междоменных запросах, вы можете обратиться кКорс-стандарт W3C;
-
хочу знать
httpсоглашение, вы можете обратиться кHTTP Tutorial;