Модераторы: Sardar, Aliance
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Объект-оболочка для запросов XMLHttpRequest, чтоб недумать об onreadystatechange ипр. 
:(
    Опции темы
Greendrake
Дата 24.2.2006, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 364
Регистрация: 14.7.2005

Репутация: нет
Всего: 6



В развитие вопроса, затронутого вот в этой теме.

Итак дано: нужен некий объект, имеющий для начала метод GETrequest(url,task), в котором task - функция, которую нужно выполнить после прихода ответа на запрос урла url по XMLHttpRequest. Потом к этому объекту добавим запросы POST для форм и т. п., но щас это не суть, просто чтоб пояснить зачем вообще понадобился именно объект. Вопросы возможного неответа сервера на запрос щас не парят, допустим что с этим проблем нет.

Вот моя попытка это реализовать:

Код

function RequestObject() {
  this.div=document.createElement('DIV');
  if (window.XMLHttpRequest) {this.XMLHttpRequest=new XMLHttpRequest();}
  else {
    try {this.XMLHttpRequest=new ActiveXObject('Msxml2.XMLHTTP');}
    catch(e) {this.XMLHttpRequest=new ActiveXObject('Microsoft.XMLHTTP');};
  };
  this.XMLHttpRequest.onreadystatechange=function() {
    if(this.XMLHttpRequest.readyState==4 && this.XMLHttpRequest.status==200) {
      this.task();
    };
  };
};

RequestObject.prototype.GETrequest=function(url,task) {
  this.task=task;
  this.XMLHttpRequest.open('GET',url,true);
  this.XMLHttpRequest.send(null);
};

var r = new RequestObject();
r.GETrequest('t.txt',function(){alert('done')});


Ругается, зараза, на строчку 9 - типа в том контексте this это нифига не RequestObject, и шо це таке this.XMLHttpRequest.readyState она не знает... Как быть подскажите плиз?

Это сообщение отредактировал(а) Greendrake - 24.2.2006, 23:27
PM MAIL   Вверх
Sardar
Дата 25.2.2006, 01:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317



Цитата(Greendrake @ 24.2.2006, 22:20 Найти цитируемый пост)
Ругается, зараза, на строчку 9

Да, всё правильно, this в функции должен указывать на XMLHttpRequest т.к. это его onreadystatechange метод smile Правда как в ИЕ, так в и в мозилле какая то магия происходит и this не всегда указывает на XMLHttpRequest, а бывает на window.

По коду, а что ты будешь делать если ответ придёт не 200? повиснешь? smile

Накидаю свой вариант, покажу smile


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Sardar
Дата 25.2.2006, 02:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317



Вот так получилось, завтра припаяю туда XSLT трансформации.

Код
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
    <title>XMLHttpRequest - simple GET</title>
<script type="text/javascript">
/**
* Собственно интервал для красоты, лучше всё таки отправлять по enter
*/
function startJob() {
   updateMyField();
   var tm=document.getElementById('tm');
   var i = 10;
   
   window.setInterval(function() {
      tm.innerHTML = --i; 
      if(i<=0) {
        updateMyField();
        i = 10;
      }
   }, 1000);

}

/**
* Логика, обновление поля, пользуем GET запрос
*/
function updateMyField() {
   var i=document.getElementById('in');
   requestGet('./serv.php?bla='+i.value, function(data) {
      if(data != null) {
        document.getElementById('out').innerHTML+="<div>Key: <b>"+i.value+"</b> - "+data+"</div>";
      } else alert("Request failed!");
   }, 3);
}


/**
* Более конкретный GET запрос + поддержка множественных попыток если 
* сеть лагает.
*/
function requestGet(url, task, attempts) {
    if(!attempts || (attempts = attempts.toFixed(0)) < 0) attempts = 0;
    if(!(attempts >= 1)) throw ("No attempts to request!"); //NaN

    function handler(url, request) {
        if(request.status < 200 || request.status > 299) {
            if(--attempts > 0) performXMLHttpRequest(url, arguments.callee, attempts);
            else task(null);
        } else task(request.responseText);
    }
    performXMLHttpRequest(url, handler);
}

/**
* Собсно функция выполняет запрос, GET или POST на указанный URL.
* Выполняет рутинные действия с XMLHttpRequest, позволяя конкретной функции
* сконцентрироваться на задаче.
* Все созданные обьекты XMLHttpRequest используються по новой.
*/
function performXMLHttpRequest(url, type, param, handler) {
    var req, ie;
    function cleaner() {
        if(req.readyState == 4) {
            //req.onreadystatechange = null; //fix IE bug
            performXMLHttpRequest.pool.push(req);
            handler([url, type, param], req);
        }
    }
    
    if(typeof window.ActiveXObject != 'undefined') {
        req = (performXMLHttpRequest.pool.length > 0)? performXMLHttpRequest.pool.pop(): new ActiveXObject("Microsoft.XMLHTTP");
        req.open(type.toUpperCase(), url, true);
        req.onreadystatechange = cleaner;
        ie = true;
    } else {
        req = (performXMLHttpRequest.pool.length > 0)? performXMLHttpRequest.pool.pop(): new XMLHttpRequest();
        req.open(type.toUpperCase(), url, true);
        req.onreadystatechange = cleaner;
        ie = false;
    }
    
    try { //catch all 404 and other errors
        if(ie && type.toUpperCase() == 'GET') req.send();
        else req.send(param? param: null);
    } catch(e) {}
    
    return req; //Warning: can be returned after 'handler' call!
}
performXMLHttpRequest.pool = [];
</script>

<style type="text/css">
#out_platf {
  padding: 5px;
  margin: 10px;
  border: 1px solid black;
  font-family: monospace;
  font-size: 12px;
  color: black;
  background-color: #f4f5db;
}
#out {
  margin: 5px;
}
</style>
</head>

<body onload="startJob();">
<div><label accesskey="s">SHA1 key: <input type="text" id="in" onkeydown="if(event.keyCode == 13) updateMyField();"></label>&nbsp;&nbsp; Update time: <span id="tm">0</span>s</div>
<div id="out_platf">Output:
  <div id="out"></div>
<div>
</body>
</html>


По теме здесь только performXMLHttpRequest и requestGet. Те кто работал с POST запросами вспомнят что нужно ещё установить заголовок Content-type, те кто работал с Оперой знают что ещё пару шаманских движений нужно сделать. Писать это всё лень, в поиск, но именно поэтому я пишу две разные функции, performGetRequest и performPOSTRequest, работающие как и performXMLHttpRequest, но имеющие "вшитые" парамерты со всеми workaround'ами. Не совсем обьектная оболочка получилась, но мне так удобней smile

Нда, на сервере по традиции хеш:
Код
<?php
  header("Content-type: text/plain");
  echo @sha1($_REQUEST['bla']);
?>


Для ленивых: http://sardar.vingrad.ru/projects/xmlhttp/index.htm


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Greendrake
Дата 25.2.2006, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 364
Регистрация: 14.7.2005

Репутация: нет
Всего: 6



Цитата(Sardar @ 25.2.2006, 01:16)
По коду, а что ты будешь делать если ответ придёт не 200? повиснешь? smile


Ну.. Этот RequestObject горячий кофэ готовить тоже не умеет, и ничего в этом страшного я не вижу. Не "200" - это скорее исключение, чем правило, и я думаю что вначале следует заточить объект под правила, а уж потом учить его готовить кофэ smile.

Так, сейчас меня больше всего вот это беспокоит:
Цитата(Sardar @ 25.2.2006, 01:16)
Правда как в ИЕ, так в и в мозилле какая то магия происходит и this не всегда указывает на XMLHttpRequest, а бывает на window.

Давайте отставим магию, телепатию и летающие тарелочки - мы имеем дело с железякой, нулями и единичками. Как объяснить это поведение? Отход от ECMA-стандарта?? Я мог бы это понять если бы только IE или Опера. Но когда FireFox, чистокровный прямой потомок родителей JavaScript выполняет стандарты хуже Оперы, думаю это повод подвергнуть сомнению наше скриптовое мировоззрение.

Добавил:

Мне удалось-таки, хоть топором, но обойти "магию" и сделать код кроссбраузерным:
Код

function RequestObject() {
  this.div=document.createElement('DIV');
  if (window.XMLHttpRequest) {this.XMLHttpRequest=new XMLHttpRequest();}
  else {
    try {this.XMLHttpRequest=new ActiveXObject('Msxml2.XMLHTTP');}
    catch(e) {this.XMLHttpRequest=new ActiveXObject('Microsoft.XMLHTTP');};
  };
  var RequestObject = this;
  var referenceToXMLHttpRequest = this.XMLHttpRequest;
  this.XMLHttpRequest.onreadystatechange=function() {
    if(referenceToXMLHttpRequest.readyState==4 && referenceToXMLHttpRequest.status==200) {
      RequestObject.task();
    };
  };
};

RequestObject.prototype.GETrequest=function(url,task) {
  this.task=task;
  this.XMLHttpRequest.open('GET',url,true);
  this.XMLHttpRequest.send(null);
};

var r = new RequestObject();
r.GETrequest('1.html',function(){alert('done')});

Но однако нездоровая это фигня..

Это сообщение отредактировал(а) Greendrake - 25.2.2006, 18:44
PM MAIL   Вверх
Sardar
Дата 25.2.2006, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317



Цитата(Greendrake @ 25.2.2006, 17:00 Найти цитируемый пост)
Этот RequestObject горячий кофэ готовить тоже не умеет

Идеалист я вижу, никгда с лагами сети не встречался smile Из опыта, примерно 10% всех твоих запросов будут приходить не с 200. Также сам ответ может быть не 200, т.к. 2хх это удачное завершение запроса, с вопросами отправляю в HTTP спецификацию.
Цитата(Greendrake @ 25.2.2006, 17:00 Найти цитируемый пост)
Мне удалось-таки, хоть топором, но обойти "магию"

Не спеши, магия в том что вызов onreadystatechange происходит не на обьекте XMLHttpRequest, т.е. this на него не указывет. Скорее всего так выходит потому, что само событие выполняеться в отдельном треде, куда ссылка твоя на XMLHttpRequest не скопировалась... Собственно создавая вот так сыслку на XMLHttpRequest и решаем "траблу".

Не уверен что RequestObject.task(); обратиться именно к локальной переменой, а не к самой функции. Также не пойму, зачем нужно создавать closure для onreadystatechange в конструкторе, при этом пользуясь полями обьекта для сохранения задачи, вместо того что бы создать это closure в GETrequest и получать task из контекста... Или ты просто этого момента, присущего скорее функциональным языкам, не понимаешь?


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Greendrake
Дата 26.2.2006, 00:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 364
Регистрация: 14.7.2005

Репутация: нет
Всего: 6



Цитата(Sardar @ 25.2.2006, 23:21)
Не уверен что RequestObject.task(); обратиться именно к локальной переменой, а не к самой функции.

Я тоже не был уверен, но решил сначала попробовать для ссылок не сочинять новых названий переменных, а использовать имеющиеся. Для самого XMLHttpRequest в контексте конструктора этот номер не прошёл в Опере, поэтому пришлось-таки назвать по-другому - с префиксом reference. А вот для самого RequestObject - прокатило smile. Почему - особо не врубился, но пока пашет.

Цитата(Sardar @ 25.2.2006, 23:21)
Также не пойму, зачем нужно создавать closure для onreadystatechange в конструкторе, при этом пользуясь полями обьекта для сохранения задачи, вместо того что бы создать это closure в GETrequest и получать task из контекста... Или ты просто этого момента, присущего скорее функциональным языкам, не понимаешь?

Потому что впоследствии я хочу добавить метод POSTrequest, и зачем же мне в обоих методах плодить одинаковые участки кода по проверке onreadystatechange? Пусть оба пользуются полями объекта - на то я его и создал, и каждый занимается исключительно своим делом. Разве не логично?

Это сообщение отредактировал(а) Greendrake - 26.2.2006, 00:20
PM MAIL   Вверх
Sardar
Дата 26.2.2006, 00:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317



Цитата(Greendrake @ 25.2.2006, 23:11 Найти цитируемый пост)
А вот для самого RequestObject - прокатило smile. Почему - особо не врубился, но пока пашет.

А ты дважды функцию вызывал? По идее после первого она может и "пропасть" вовсе smile
Добавлено @ 00:45
Цитата(Greendrake @ 25.2.2006, 23:11 Найти цитируемый пост)
Разве не логично?

Нет, не логично, в мире "полу декларативных" языков не логично, т.к. то что ты написал, не есть "одно определение функции", это участок кода (closure), что у каждого обьекта будет свой (физически). Вообщем вот пример, если не понял, забудь:

Код
RequestObject.prototype.initReadyStateChangeEvent=function(task) {
  var referenceToXMLHttpRequest = this.XMLHttpRequest;
  this.XMLHttpRequest.onreadystatechange=function() {
   if(referenceToXMLHttpRequest.readyState==4 && referenceToXMLHttpRequest.status==200) {
      task();
    };
  };
}

//GETrequest(url, task)
//.....
this.initReadyStateChangeEvent(task); //задача установлена

//POSTrequest(url, task)
//.....
this.initReadyStateChangeEvent(task);



--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Greendrake
Дата 26.2.2006, 00:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 364
Регистрация: 14.7.2005

Репутация: нет
Всего: 6



Цитата(Sardar @ 26.2.2006, 00:36)
А ты дважды функцию вызывал? По идее после первого она может и "пропасть" вовсе smile

Хм, возможно. Поимею ввиду.

Тут с этим кодом обнаружил ещё одну неприятную пакость от Оперы. Когда тестишь код впервые - всё нормально. Обновляешь - работает. Но стоит выйти из Оперы и запустить снова - не пашет! Помогает только очистка кэша. Это - если в HTML стоит
Код

<meta http-equiv="Pragma" content="no-cache">

если этот тег убрать, то работает с каждым запуском без очистки кэша, но: после алерта "done", страница продолжает думать (висят часы песочные) - как бы продолжает загружаться. Останавливаешь крестиком, обновляешь - работает. При перезапуске всё повторяетя (после первого раза - думает). Бред какой-то. Что это такое? Версия Оперы 8.5.

Это сообщение отредактировал(а) Greendrake - 26.2.2006, 00:59
PM MAIL   Вверх
Sardar
Дата 26.2.2006, 01:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317



url твой должен меняться, иначе берёться инфа из кеша. А вот почему подвисает не знаю...
Но за то ты видишь что такое лаги сети и почему код должен быть немного другим чем у тебя smile


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Greendrake
Дата 26.2.2006, 15:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 364
Регистрация: 14.7.2005

Репутация: нет
Всего: 6



Цитата(Sardar @ 26.2.2006, 00:36)
Вообщем вот пример

Уряя.. Воспользовался примером, соорудил весчь. Выражаю спасибу. Вот:

Код

function RequestObject() {
  this.div=document.createElement('DIV');
  if (window.XMLHttpRequest) {this.XMLHttpRequest=new XMLHttpRequest();}
  else {
    try {this.XMLHttpRequest=new ActiveXObject('Msxml2.XMLHTTP');}
    catch(e) {this.XMLHttpRequest=new ActiveXObject('Microsoft.XMLHTTP');};
  };
};
RequestObject.prototype.initReadyStateChangeEvent=function(task) {
  var referenceToXMLHttpRequest = this.XMLHttpRequest;
  this.XMLHttpRequest.onreadystatechange=function() {
   if(referenceToXMLHttpRequest.readyState==4 && referenceToXMLHttpRequest.status==200) {
      task();
    };
  };
}
RequestObject.prototype.GETrequest=function(url,task) {
  this.initReadyStateChangeEvent(task);
  this.XMLHttpRequest.open('GET',url,true);
  this.XMLHttpRequest.send(null);
};
var r = new RequestObject();
r.GETrequest('1.html',function(){alert('done')});

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Форум для вопросов, которые имеются в справочниках, но их поиск вызвал затруднения, или для разработчика требуется совет или просьба отыскать ошибку. Напоминаем: 1) чётко формулируйте вопрос, 2) приведите пример того, что уже сделано, 3) укажите явно, нужен работающий пример или подсказка о том, где найти информацию.
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | JavaScript: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0544 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.