Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Очень странное поведение (https://javascript.ru/forum/misc/21201-ochen-strannoe-povedenie.html)

melky 03.09.2011 02:12

popov654, тут очень много текста. не могли бы вы описать проблему в двух предложениях, с кодом ?)

popov654 03.09.2011 02:29

Цитата:

Вопрос в другом. Вот есть у меня массив этих объектов, и пока все запросы не отправлены полностью, дальнейшее выполнение кода нужно ЗАБЛОКИРОВАТЬ, чтобы браузер не ушёл на другой адрес. Поскольку обычный setTimeout(), как здесь уже обсуждалось, не останавливает поток выполнения, я использую логическую переменную. Но получается глупо: как только один запрос отправится, она устанавливается в true. Если есть ещё хотя бы один незавершённый запрос, его "прослушиватель", повешенный на setInterval(), конечно перепишет переменную на false...

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

Цитата:

Есть ещё мысль повесить на setInterval полный обход массива... Но мне это кажется каким-то страшно нерациональным. Ведь если большая часть запросов давно отправлена, мы будем гулять по массиву зря (следовательно, потеря производительности, т.к. запросов может быть до тучи).
Заводить ещё один массив для хранения индексов успешно отправленных - тоже вроде как глупо, по понятным причинам...

Я убрал лишний текст (сорри за повтор). Код приводить вряд ли есть смысл: там ровно то, что написано выше, только ещё менее наглядно (например, потому что логических флага зачем-то сделано два).

popov654 03.09.2011 05:15

Вот код функции посылки запросов:
function saveChanges() {
   var imgs = new Array();
   for (var i = 0; i < queries.length; i++) {
      imgs.push(new Image())
      imgs[i].src = queries[i]
   }
   var tries = 0;
   var timer = setInterval(function() {
      tries++
      requestComplete = true
      for (var i = 0; i < imgs.length; i++) {
         if (!imgs[i].complete) {
            requestComplete = false
         }
      }
      if (requestComplete) {
         clearInterval(timer);
         alert('Данные сохранены! Запросов выполнено: ' + queries.length)
         queries = []
      } else if (tries > 8) {
         clearInterval(timer);
      }
   }, 100);
   return false;
}

var requestComplete = false



А вот код, который выполняет ожидание перед сменой блока:

elem.onclick = function() {
      if (queries.length && confirm('Вы хотите сохранить введённые данные?')) {
         saveChanges()
         var tries = 0;
         var timer = setInterval(function() {
            tries++
            if (requestComplete) {
               requestComplete = false
               clearInterval(timer)
               document.form1.action = 'edit.php'
               document.form1.from.value = pages * 25
               document.form1.submit()
            }
            if (tries > 10) {
               clearInterval(timer)
               alert('Ошибка запроса')
            }
         }, 200);
      } else {
         document.form1.action = 'edit.php'
         document.form1.from.value = pages * 25
         document.form1.submit()
      }
   }


Этот блок кода отвечает за переадресацию на последний блок данных, поэтому замыкания тут не используются.

Я отредактировал неудачные на мой взгляд места, это исправленная версия. Однако на длинных запросах (29 записей сразу например) почему-то вылетает алерт с неудачной отправкой (при одиночных запросах всё ОК).

Добавлено спустя 5 минут:

Всё! Работает! Я всего лишь увеличил таймауты, и этого оказалось достаточно. Вот итоговый код:

function saveChanges() {
   var imgs = new Array();
   for (var i = 0; i < queries.length; i++) {
      imgs.push(new Image())
      imgs[i].src = queries[i]
   }
   var tries = 0;
   var timer = setInterval(function() {
      tries++
      requestComplete = true
      for (var i = 0; i < imgs.length; i++) {
         if (!imgs[i].complete) {
            requestComplete = false
         }
      }
      if (requestComplete) {
         clearInterval(timer);
         alert('Данные сохранены! Запросов выполнено: ' + queries.length)
         queries = []
      } else if (tries > 8) {
         clearInterval(timer);
      }
   }, 500);
   return false;
}

var requestComplete = false


elem.onclick = function() {
      if (queries.length && confirm('Вы хотите сохранить введённые данные?')) {
         saveChanges()
         var tries = 0;
         var timer = setInterval(function() {
            tries++
            if (requestComplete) {
               requestComplete = false
               clearInterval(timer)
               document.form1.action = 'edit.php'
               document.form1.from.value = pages * 25
               document.form1.submit()
            }
            if (tries > 3) {
               clearInterval(timer)
               alert('Ошибка запроса')
            }
         }, 4000);
      } else {
         document.form1.action = 'edit.php'
         document.form1.from.value = pages * 25
         document.form1.submit()
      }
   }

popov654 03.09.2011 05:23

Чёрт... Рано обрадовался. Два столбца по 29 запросов уже не тянет. А должна тянуть максимум 25 таких столбцов!

Самое обидное, что пока я не ввёл эти проверки, запросы шли быстрее раз так в пять. :(

Так и знал, что линейный обход - ужасный способ. И что мне теперь делать? Может, ничего не проверяя, поставить таймаут побольше (секунд 10)? Но тогда ждать юзеру придётся даже при маленьких модификациях базы, даже когда запрос всего один :(

melky 03.09.2011 12:00

вы проверяете завершенность по интервалу - ай ай ай. :nono:
function saveChanges(callback) {
    var imgs = new Array(), i = 0, max = queries.length - 1;
    
    var timer = setInterval(function(){
        imgs.push(new Image);
        
         // обработчик загрузки для последней картинки
        if (i === max) imgs[i].onload = callback( imgs );
        
        imgs[i].src = queries[i];

        if( ++i > max ) clearInterval(timer);
        
    }, 100);
}


elem.onclick = function() {
    // для экономии места повторяющиеся операции занёс в функцию
    function normForm() {
        var a = document.form1;
        a.action = 'edit.php';
        a.from.value = pages * 25
        a.submit();
    };
    
    if (queries.length && confirm('Вы хотите сохранить введённые данные ? ')) {
        
        saveChanges(/*выполнится по завершении запроса*/function(a) {
            
            // a - массив картинок.
            alert('Данные сохранены! Запросов выполнено : '+a.length);
            queries = [];
            normForm();
        });

    } else {
        normForm();
    }
}

popov654 04.09.2011 16:24

Спасибо) Не сообразил, что onload есть не только у body :)
Туплю)

P.S. Там код этого обработчика несколько сложнее (потому что при нажатии на разные кнопки вызываются разные блоки), но я допилю, всё ОК :)

popov654 04.09.2011 16:25

Жаль, плюсик Вам в карму не отправить :)

popov654 04.09.2011 19:39

Да ёлки-палки... :-E
После такой переделки у меня теперь та же ситуация, что была в самом начале: пишется, но не всё.

Я изучил лог-файл сервера. В большинстве случаев не хватает одного запроса, иногда один запрос отправляется на адрес undefined. Странно...

popov654 04.09.2011 19:46

Ну я так и думал. Надо было поменять эти две строки местами:

if (i == max) imgs[i].onload = callback( imgs );
imgs[i].src = queries[i];


Походу до присваивания src интерпретатор считал рисунок загруженным (как раз по адресу undefined), и запускался callback, очищающий весь массив адресов запроса. В итоге запрос либо не уходил вовсе, либо уходил на адрес undefined.

Настораживает ещё вот какой факт: иногда помимо запроса undefined не хватало ещё одного запроса. Поэтому вопрос к Вам: Вы уверены, что все предыдущие запросы успеют дойти? Обработчик-то мы привязали только к последнему :)

melky 04.09.2011 20:29

как они могут не дойти? картинки создаются в цикле - значит запросы так же создаются в цикле. посмотрите вкладку Network в инструменте веб-мастера


Часовой пояс GMT +3, время: 22:45.