AJAX : readyState, load и readystatechange

AJAX : readyState, load и readystatechange

Как мы все знаем работа с технологией AJAX требует использования события readystatechange. Теоретически мы так же можем использовать событие load, но как мы увидим далее IE до версии 9 его не поддерживает в данном контексте. Событие readystatechange и свойство readyState, имеют несколько особенностей при использовании.

Как правило эти особенности не попадаются нам на глаза, но если мы решим работать с AJAX без использования, какого либо уровня абстракции типа JQuery и ей подобных, то нам не помешает дополнительная информация о readyState и его состояниях отличных от 4, а так же других возможных подводных камнях.

    В статье использованы следующие версии браузеров:

  • Chrom: 20.0.1132.47 m
  • Opera: 12.00
  • IE: 7,8,9
  • FireFox: 13.0.1
  • Safari: 5.1.7 (7534.57.2)

AJAX : readyState

Событие readystatechange возникает, когда изменяется свойство AJAX запроса - readyState. Это свойство может иметь четыре состояния, которые теоретически работают так, как показано ниже. Практически же, браузеры, увы не всегда следуют этому стандарту. Итак, значения readyState:

  • 0 Uninitialized - метод open() ещё не был вызван.
  • 1 Loading - метод send() ещё не был вызван.
  • 2 Loaded - метод send() был вызван,заголовки и статус - доступны.
  • 3 Interactive - Загрузка данных, responseText уже содержит какую то часть данных.
  • 4 Completed - Завершение всех операций.

Значение 4 свойства readyState является эквивалентом события load, а так же является стандартной частью любого AJAX сценария. Значение 3 свойства readyStates хорошо бы подошло для разработки прогресс бара, кабы не было проблем с совместимостью. Адекватных подсчётов уже загруженного контента удалось добиться только в Chrome и Safari, FireFox Opera предоставляли уже конечные значения, а от IE я вообще не добился никакой реакции.

Тем не менее, давайте проверим следующий кусок кода. Вы скорее всего ожидали бы увидеть такой прядок состояний: 1, 2, 3 и 4.

// Так как GET - запросы могут кэшироваться мы применим приём с добавлением временной метки
// таким образом url - всегда будет разным:
xmlhttp.open("GET","somepage.xml?t=" + (new Date()).getTime(),true);
xmlhttp.onreadystatechange = checkData;
xmlhttp.send(null);

function checkData() {
	console.log(xmlhttp.readyState);
}

    Результат:

  • Chrom : 2-3-4 (ОЙ!)
  • Opera: 2-3-4 (ОЙ!)
  • Explorer 7: 1-2-4-3 (Нормально)
  • Explorer 8: 1-2-4-3 (Нормально)
  • Explorer 9: 1-2-3-4 (Нормально)
  • Mozilla: 1-2-4-3 (Нормально)
  • Safari: 2-3-4 (ОЙ!)

А теперь давайте перенесём подключение обработчика события в другую точку кода и посмотрим как изменится поведение браузеров:

xmlhttp.onreadystatechange = checkData;
xmlhttp.open("GET","somepage.xml?t=" + (new Date()).getTime(),true);
xmlhttp.send(null);

function checkData() {
	console.log(xmlhttp.readyState);
}

    Результат:

  • Chrom : 1-2-3-4 (Нормально)
  • Opera: 1-2-3-4 (Нормально)
  • Explorer 7: 1-1-2-3-4 (ОЙ!)
  • Explorer 8: 1-1-2-3-4 (ОЙ!)
  • Explorer 9: 1-1-2-3-4 (ОЙ!)
  • Mozilla: 1-1-2-3-4 (ОЙ!)
  • Safari: 1-2-3-4 (Нормально)

Все браузеры теперь добавили в начало последовательности дополнительное состояние readyState - 1. Explorer и Mozilla, правда сделали это по-своему... дважды, и это странно, потому, что переход состояния от 1 к 1 это вовсе не "change" и не должно вызывать обработчик onreadystatechange. Но зато при таком раскладе мы теперь наблюдаем все состояния в правильном порядке. Кстати этот вариант установки обработчика до вызова метода open, считается правильным.

Давайте снова перенесём точку подключения обработчика события в коде:

xmlhttp.open("GET","somepage.xml?t=" + (new Date()).getTime(),true);
xmlhttp.send(null);
xmlhttp.onreadystatechange = checkData;

function checkData() {
	console.log(xmlhttp.readyState);
}

    Результат:

  • Chrom : 2-3-4 (ОЙ!)
  • Opera: 2-3-4 (ОЙ!)
  • Explorer 7: 2-4-3 (ОЙ!)
  • Explorer 8: 2-4-3 (ОЙ!)
  • Explorer 9: 2-3-4 (ОЙ!)
  • Mozilla: 2-3-4 (ОЙ!)
  • Safari: 2-3-4 (ОЙ!)

Итог: все испытуемые лопухнулись, все потеряли состояние 1... но зато сделали это коллективно и единогласно! В общем вывод один: все браузеры имеют глюки в отношении readyState, одно только радует, что хотя бы ключевое значение - 4 присутствует во всех случаях. А так же устанавливайте обработчик до вызова метода open()

readystatechange

Рассмотрим само событие readystatechange:

xmlhttp.open("GET","somepage.xml?t=" + (new Date()).getTime(),true);
xmlhttp.onreadystatechange = checkData;
xmlhttp.send(null);

function checkData(e) {
	var evt = e || window.event,
    	rs  = xmlhttp.readyState || "None";
	alert(evt.type + ' ' + rs);
}

    Результат:

  • Chrom : evt.type = readystatechange 2, ... 3, ... 4 (ОЙ!)
  • Opera: evt.type = readystatechange 2, ... 3, ... 4 (ОЙ!)
  • Explorer 7: evt.type = 1, ... 2, ... 3, ... 4 (ОЙ!)
  • Explorer 8: evt.type = 1, ... 2, ... 3, ... 4 (ОЙ!)
  • Explorer 9: evt.type = readystatechange 1, ... 2, ... 3, ... 4 (Нормально)
  • Mozilla: evt.type = readystatechange 1, ... 2, ... 3, ... 4 (Нормально)
  • Safari: evt.type = readystatechange 2, ... 3, ... 4 (ОЙ!)

Увы для IE 7-8 свойство type - является пустой строкой... ну ладно хоть ошибку не вызывает

load

IE до версии 9 не имеет такого события как load у объекта xmlhttprequests, в остальных же случаях его можно рассматривать как подмножество событий readystatechange. load вызывается, когда страницы загружена полностью, что эквивалентно: readyState 4 completed.

Давайте попробуем следующий кусок кода:

xmlhttp.open("GET","somepage.xml?t=" + (new Date()).getTime(),true);
xmlhttp.onload = checkData;
xmlhttp.send(null);

function checkData(e){
	var evt = e || window.event;
	var rs = xmlhttp.readyState || "None";
	alert(evt.type + ' ' + rs);
}

    Результат:

  • Chrom : load 4
  • Opera : load 4
  • Explorer 7: Ничего!
  • Explorer 8: Ничего!
  • Explorer 9: load 4
  • Mozilla: load 4
  • Safari: load 4

Как видим все современные браузеры поддерживают событие load, кроме IE до версии 9. В целом на сегодняшний день с поддержкой технологии AJAX, на мой взгляд дела обстоят значительно лучше, чем на момент написания прообраза этой статьи: XMLHTTP notes Изначально я просто хотел сделать перевод статьи указанной по ссылке, но потом потестив примеры на современных браузерах и используя в тестах не alert(), а console.log() и получив иные результаты - я решил провести своё мини исследованиеНадеюсь мои изыскания сэкономят кому то из вас время при разработке вэб приложений.

Добавить комментарий


Защитный код
Обновить



Кто на сайте
Сейчас 179 гостей онлайн