
11.04.2015, 12:45
|
Аспирант
|
|
Регистрация: 12.04.2013
Сообщений: 86
|
|
Поправить XMLHttpRequest
Привет. Решил отказаться от jquery.ajax() и начеркать что-нибудь своё. Вот что получилось:
var _Request = function(options) {
options = {
type: options.type.toUpperCase() || 'POST',
url: options.url || '',
dataType: options.dataType.toUpperCase() || 'HTML',
param: options.param || '',
success: options.success || function(){},
error: options.error || function(){}
}
var xhr;
var rand = Math.floor(Math.random( )*(9999999+1));
if(window.XMLHttpRequest) {
try { xhr = new XMLHttpRequest(); }
catch (e){}
} else if (window.ActiveXObject) {
try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
catch(e) {}
try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
catch(e) {}
try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }
catch(e) {}
try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
catch(e) {}
}
if(options.type == "GET") {
xhr.open(options.type, options.url+'?'+options.param+'&rnd='+rand, true);
} else if(options.type == "POST") {
xhr.open(options.type, options.url, true);
} else { return; }
if(options.dataType == 'HTML') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
} else if(options.dataType == 'JSON') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
} else { return; }
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
if(options.dataType == 'HTML') {
return options.success(xhr.responseText);
} else if(options.dataType == 'JSON') {
var data = JSON.parse(xhr.responseText);
if(data != '' && data.length > 0) {
return options.success(data);
} else {
return options.error('error');
}
}
} else {
return options.error('error');
}
} else {
return options.error('error');
}
}
if(options.type == "GET") {
xhr.send(null);
} else if(options.type == "POST") {
xhr.send(options.param+'&rnd='+rand);
} else { return; }
}
ИСПОЛЬЗОВАНИЕ:
_Request({
type: 'GET',
dataType: 'JSON',
url: '/script.php',
param: 'user=stashappy',
success: function(data) {
alert(data.result);
}, error: function(data) {
alert('ERROR');
}
});
В принципе всё работает отлично, за исключением одного момента. Не хватает более правильной обработки ошибок, в случаях, когда php-файл-обработчик отсутствует на сервере или когда обработчик возвращает пустой результат. Запрос к следующему файлу, вызовет синтаксическую ошибку в JS коде:
script.php
<?php
exit;
?>
Прошу вашей помощи по решению данной задачи. Также хотелось бы узнать, могу ли я использовать в данном варианте событие abort(), для отмены запроса. Если нет, то как можно доработать данный JS код? Пример:
// примерно таким образом
var query = _Request({
// бла бла бла
});
query.abort(); // отменяем запрос
|
|

11.04.2015, 13:02
|
Кандидат Javascript-наук
|
|
Регистрация: 31.03.2015
Сообщений: 113
|
|
Сообщение от 1lider
|
отменяем запрос
|
Что значит отменяем? Как ты можешь отменить его, если он уже сделан?
|
|

11.04.2015, 13:07
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
if(!!data) { ... }
if(data != '' && data.length > 0) - а если так 2 или более пробелов в ответе сервера значит ОК? И это проверяется после JSON.parse.
try {
var data = JSON.parse(xhr.responseText)
} catch (e) {
//ошибка формата
}
Последний раз редактировалось laimas, 11.04.2015 в 13:13.
|
|

11.04.2015, 13:25
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
Сообщение от theKingOfJava
|
Что значит отменяем? Как ты можешь отменить его, если он уже сделан?
|
Метода .abort() обрывает текущий запрос. В IE вызов abort() не обрывает соединение, а оставлять его в подвешенном состоянии на некоторый таймаут (20-30 секунд).
Лимит на соединения не более 2 одновременных соединений с одним доменом-портом. Если два соединения уже висят по таймаут, то третье открыто не будет, пока одно из них не умрет.
|
|

11.04.2015, 13:54
|
Аспирант
|
|
Регистрация: 12.04.2013
Сообщений: 86
|
|
Сообщение от laimas
|
if(data != '' && data.length > 0) - а если так 2 или более пробелов в ответе сервера значит ОК? И это проверяется после JSON.parse.
|
Можно убрать пробелы при проверке и сделать так:
if(xhr.responseText.replace(/\s+/g, '') != '' && xhr.responseText.replace(/\s+/g, '').length > 0) {
try {
var data = JSON.parse(xhr.responseText);
return options.success(data);
} catch (e) {
return options.error('error');
}
} else {
return options.error('error');
}
По поводу события abort().
// примерно таким образом
var query = _Request({
// бла бла бла
});
query.abort(); // отменяем запрос
Могу ли я провернуть подобное используя свой код? Вопрос возник, потому что объект xhr объявляется внутри функции _Request(), которая помещается в переменную query. Можем ли мы в данном случае применить query.abort();, чтобы добраться до объекта xhr и отменить тем самым запрос?
|
|

11.04.2015, 16:40
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
if(xhr.responseText.replace(/\s+/g, '') != '' && xhr.responseText.replace(/\s+/g, '').length > 0) - это то зачем?
Можем ли мы в данном случае применить query.abort()
А попробуйте в своем случае.
А вообще, может задаться вопросом, а с какой целью требуется прерывать соединение? Судя по коду вы хотите и древних IE, но тогда надо учесть и их поведение.
Здесь в учебнике не нашел описания проблем (может и не там искал), но в сети много, например здесь.
Ну и тогда уж погружайтесь в ООП.
|
|

12.04.2015, 08:17
|
Аспирант
|
|
Регистрация: 12.04.2013
Сообщений: 86
|
|
Цитата:
|
А попробуйте в своем случае.
|
Попробовал. Я так и предполагал, что в данном случае это не даст результата. Потому что событие abort() необходимо применить непосредственно к созданному нами объекту XHR. А мы его применяем к функции _Request(). Как реорганизовать данный программный код так, чтобы query.abort() отменял наш открытый запрос xhr.open() ?
|
|

12.04.2015, 08:30
|
Профессор
|
|
Регистрация: 14.01.2015
Сообщений: 12,989
|
|
Как реорганизовать данный программный код так
Либо начните с этого, либо объявляйте объект глобально.
А вообще, может лучше таймаут задавать свой, по истечении которого браузер сам закроет соединение. Ну не ради же интереса вам нужен abort().
|
|

12.04.2015, 09:05
|
Аспирант
|
|
Регистрация: 12.04.2013
Сообщений: 86
|
|
Сообщение от laimas
|
ибо начните с этого,
|
Попробую начать с этого.
Сообщение от laimas
|
Ну не ради же интереса вам нужен abort()
|
На примере сайта OZON.RU. Если в поиске начать вводить ключевое слово ПУШКИН, то под строкой поиска, по мере написания этого слова, будет неоднократно всплывать окошко с предварительными результатами поиска. То же самое происходит и в поисковиках, когда в строку поиска, начинаешь вводить какое-либо ключевое слово и при этом, снизу выпадает список возможных вариантов. У себя сделал что-то подобное.
Задача: по мере того, как пользователь будет вводить ключевое слово в строку поиска, нужно отменять старые ajax запросы к серверу и формировать новый, на основе которого и выводить выпадающий список возможных вариантов поиска.
Для этого я и пытаюсь добавить событие abort(). Чтобы иметь возможность отменить ещё невыполненный запрос с ключевым словом "ПУШ", и сформировать новый запрос с ключевым словом "ПУШК", если пользователь дописал в строку поиска букву "К".
|
|

12.04.2015, 10:05
|
Аспирант
|
|
Регистрация: 12.04.2013
Сообщений: 86
|
|
Всё оказалось очень просто. Немного подумав пришёл к выводу, что надо было просто добавить return xhr; сразу после открытия нашего запроса. Вот так:
function _Request(options) {
options = {
type: options.type.toUpperCase() || 'POST',
url: options.url || '',
dataType: options.dataType.toUpperCase() || 'HTML',
param: options.param || '',
success: options.success || function(){},
error: options.error || function(){}
}
var xhr = false;
var rand = Math.floor(Math.random( )*(9999999+1));
if(window.XMLHttpRequest) {
try { xhr = new XMLHttpRequest(); }
catch (e) {}
} else if (window.ActiveXObject) {
try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
catch(e) {}
try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
catch(e) {}
try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }
catch(e) {}
try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
catch(e) {}
}
if(xhr) {
if(options.url != '') {
if(options.type == "GET") {
xhr.open(options.type, options.url+'?'+options.param+'&rnd='+rand, true);
} else if(options.type == "POST") {
xhr.open(options.type, options.url, true);
} else {
return options.error('error');
}
} else {
return options.error('error');
}
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
if(options.dataType == 'HTML') {
return options.success(xhr.responseText);
} else if(options.dataType == 'JSON') {
if(xhr.responseText.replace(/\s+/g, '').length > 0) {
try {
var data = JSON.parse(xhr.responseText);
return options.success(data);
} catch (e) {
return options.error('error');
}
} else {
return options.error('error');
}
} else {
return;
}
} else {
return options.error('error');
}
} else {
return options.error('error');
}
}
if(options.type == "GET") {
xhr.send(null);
return xhr; // ЗДЕСЬ
} else if(options.type == "POST") {
xhr.send(options.param+'&rnd='+rand);
return xhr; // И ЗДЕСЬ
} else {
return options.error('error');
}
} else {
return options.error('error');
}
}
Использование:
var query = _Request({
type: 'GET',
dataType: 'JSON',
url: '/script.php',
param: 'user=stashappy',
success: function(data) {
alert(data.result);
}, error: function(data) {
alert('ERROR');
}
});
Отмена запроса:
query.abort();
|
|
|
|