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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Быстрые простые запросы XMLHttpRequest, наблюдаем эффект копирования контекстов 
:(
    Опции темы
Sardar
Дата 18.2.2006, 00:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


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

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



Пишу вебинтерфейс к одной железке, детали не важны, известно что можно загружать целые статичные страницы и считывать значение сенсоров читая их "как файлы". Представим что сенсоров много, после загрузки делаем массу запросов параллельно, которые затем ещё каждые пол минуты обновляються.

Суть топа: рассмотреть поближе копирование обьектов если существует более одного треда в окружении JS. Также пишем проще. Отказываемся от сложных обьектов wrapper'ов вокруг XMLHttpRequest что "могут делать всё", накаждый запрос нам нужно считать значение одного сенсора, что отдаёт его просто числом (текстом). Это очень упрощает как серверную сторону так и клиента, на сервере никаих скриптов (PHP) и т.п. нет, в железке памяти то всего 215кб доступно smile

Также есть ещё и сервисы что принимают и получают списки пар ключ=>значение, для них мы пишем отдельный код! Почему? Потому что это скрипты, общая абстракция может обойтись в 20кб кода (как надоело это видеть), что не удобно в использовании и пощти полностью отражает работу XMLHttpRequest строя некий общий обьект что будет вести себя одинакого на всех браузерах. Если пишем для котлет одну короткую функцию, а для булочек другую, то поймём зачем нужны скрипты smile Опрос сервисов почти такой же как опрос сенсоров, потому в топе опущу.

Задача: написать некую функцию которая может асинхронно загрузить некий путь/url, при этом освободим нас от деталей, передав нам результат когда всё будет готово. При этом можно делать сколько угодно паралелльных запросов. Для каждого запроса можно задать количество попыток если загрузка происходит не удачно.

Этого достаточно что бы написать:
Код
/**
* Обновить значение сенсора.
* Параметрами передаём имя сенсора, например: temperatuur.kamer, и поле(div)
* куда записать значение.
*/
function updateSensor(name, field) {
    var req = requestSensorValue(name);

    req.request(function(value) { //собсно загрузка значения
        //alert("in: "+req.inProgress());
        if(value === null) { //on error
            reportError("Server request failed!");
            field.innerHTML = "<span class='value_error'>NA</span>";
        } else field.innerHTML = parseInt(value);
    }, 3); //3 попытки
    //window.setTimeout(function() {alert("timed last: "+req.inProgress()+", "+(req.req == null));}, 3000);
}

Функция подгружает значение сенсора в заданное поле, если за 3 попытки не получилось (железяка может обслуживать не более 20 коннектов), то выставляем NA до следующих 30 секунд.

Функция requestSensorValue возвращает обьект ValueRequest, суть которого в дополнении общей функции загрузки возможностью множественных поптыток. Реализация проста. Рассмотрим саму загружающую функцию, всего одну функцию smile
Код
function performXMLHttpRequest(url, handler) {
    var req, ie;
    function cleaner() { //очищающий closure
        if(req.readyState == 4) {
            //req.onreadystatechange = null; //fix IE bug
            performXMLHttpRequest.pool.push(req);
            handler(url, req);
        }
    }
    
    if(typeof window.ActiveXObject != 'undefined') {
        req = (performXMLHttpRequest.pool.length > 0)? performXMLHttpRequest.pool.pop(): new ActiveXObject("Microsoft.XMLHTTP");
        req.open('GET', url, true);
        req.onreadystatechange = cleaner;
        ie = true;
    } else {
        req = (performXMLHttpRequest.pool.length > 0)? performXMLHttpRequest.pool.pop(): new XMLHttpRequest();
        req.open('GET', url, true);
        req.onreadystatechange = cleaner;
        ie = false;
    }
    
    try { //catch all 404 and other errors
        if(ie) req.send();
        else req.send(null);
    } catch(e) {}
    
    return req; //Warning: can be returned after 'handler' call!
}
performXMLHttpRequest.pool = [];

Код предельно прост. Имеем пул XMLHttpRequest обьектов что динамически растёт если много одновременных запросов, из пула отработанные XMLHttpRequest обьекты используються вновь. Такой подход сохраняет память. Вся работа основываеться на факте что:
  • таймаут реализован в коннектах браузера, нам этого делать не нужно (минимум половина всех программистов пытаються сделать свой таймаут)
  • что бы не случилось состояние (readyState == 4) произойдёт, что не означает успешного завершеия операции. Успех проверяем по request.responseBody != null
Всё предельно просто. Для приложений Mozilla only нет надобности в проверке readyState, есть хорошие события onload, onerror и наверное самое вкусное onprogress - позволяет сделать полоску загрузки! smile

Кто то скажет "так ведь не делает POST запросов!", да не делает, для POST (использую в опросе сервисов, а не сенсоров), пишем ещё одну такую функцию дополненную сериализацией аргументов в тело запроса. Можно обе функции собрать в единую, но она может стать сложней в использовании, дело вкуса, главное не большой обьект с длиннющим API что никогда не будет использоваться, а сам запрос не удобен smile

Собственно эту функцию и хотел показать, т.к. считаю такой подход написания скриптов проще и удобней чем исать кучу обьектов в "чистом ООП стиле".

Проблемы: уже отписал в этой теме:
http://forum.vingrad.ru/index.php?showtopi...st&p=648297

в результате копирования обьекта ValueRequest, что собственно держит в поле XMLHttpRequest и снимает responseText, получаеться что поле req не обнуляеться. В результате глючит inProgress функция, что пришлось "адаптировать" под этот глюк. Сам

Код
//выреазал доку что бы покороче
function ValueRequest(path) {
    this.path=path;
    this.req = null;
}

//собственно сам запрос, функция примёмник и количество попыток
//можно было вобще обойтись без ValueRequest оставив только эту функцию,
//но уж больно хотелось сохранить abort() метод
ValueRequest.prototype.request = function(receiver, attempts) {
    if(this.inProgress()) throw "ValueRequest.send: request is already in progress!";
    if((attempts = attempts.toFixed(0)) < 0) attempts = 0;
    if(!(attempts >= 1)) throw "No attempts to request!"; //NaN
    
    var slf=this;
    function handler(url, request) {
        if(request.responseBody == null) {
            if(--attempts > 0) slf.req = performXMLHttpRequest(slf.path, handler);
            else {
                slf.req = null;
                receiver(null);
            }
        } else {
            slf.req = null; //запомним строчку, обнуляем поле req!
            receiver(request.responseText.replace(/^\s+/, '').replace(/\s+$/, ''));
            alert("equalilty: "+(slf.req == null));
        }
    }
    this.req = performXMLHttpRequest(this.path, handler);
}

//не пользую, но храню "на всякий"
ValueRequest.prototype.abort = function() {
    if(this.req == null) return;
    this.req.abort();
    this.req = null;
}

//вот здесь проблема в копировании обьекта, поле req не обнуляеться
ValueRequest.prototype.inProgress = function() {
    //if(this.req != null) alert("in progress: "+this.req.readyState);
    //else alert("in progress: null");
    return (this.req != null);
}

Раскоментируем все alert'ы, замечаем что поле req обнуляеться, в коде что исполняеться в треде от XMLHttpRequest поле действительно null, это видим и в updateTemperatuur(). В то же время код что выполняться в "основном треде", а именно присваивание XMLHttpRequest в поле req, и таймаут на 3 секунды, видим что поле req не обнуляеться. Пока только одно обьяснение: обьект ValueRequest копируеться, это наблюдаеться как в ИЕ так и в Мозилле.

Весь код с тестами здесь: http://sardar.vingrad.ru/wtw/index.htm

P.S. чесно пытался покороче... пишу в последнее время маны на голландском, начинаю страдать словоблудием... smile


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


 




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


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

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