JS Ajax onreadystatechange не определен, хотя объект существует - PullRequest
2 голосов
/ 01 января 2012

Я борюсь с этим уже один день, и я буду очень благодарен, если буду ходить по кругу и помогать :-)

Аннотация
Асинхронный ajax вызывает cgi с переменными resolver и fqdn, чтобы вернуть разрешение dns против этой пары. (возвращает вывод dig @resolver $ fqdn)

Задача
В firebug я вижу, что запросы get запускаются асинхронно, а ответы в браузере ожидаемые. Однако я не могу поместить ответы в правильные div в doc, так как onreadystatechange не распознает объекты.

Примечание
Помимо того, что я перебираю массив объектов, кажется, что все они запускаются мгновенно, даже если задержка между итерациями установлена.

Ниже приведен код с моими комментариями
Поскольку resolver - это массив, я создал массив объектов xmlhttprequest.

function resolve() { 
     var numofres = 6;
     var arr = new Array;
     arr[0] = "192.168.1.11";
     arr[1] = "8.8.8.8";
     arr[2] = "8.8.4.4";
     arr[3] = "159.134.0.1";
     arr[4] = "159.134.0.2";
     var len = arr.length;
     var ax  = new Array(); //creating ax as an array 
     for (var i=0; i<=len; i++) {  //iterating through the length of resolvers array
         ax[i] = new XMLHttpRequest(); //assigning to each item in array new object
         //alert(ax[i]); // shows that object exists 
         ax[i].onreadystatechange = function(){ 
              /*=== 
              problem is above - firebug will show:
              **Uncaught TypeError: Cannot read property 'readyState' of undefined**
              **ax.(anonymous function).onreadystatechangehello.cgi:30** 
              oddly it will still populate divs inner html  with 'loading +1 '
              albeit regardless of readystate code (can be 4 or anything else )
              It perplexes me why i is thought as a function? 
              =====*/
              // alert(i);  //if this is enabled I will see readyState==4 populated correctly
              if (ax[i].readyState != 4) {
                   document.getElementById('return_table_'+i).innerHTML="loading "+i;
              }
              if(ax[i].readyState == 4){
                  // get data from the server response
                  var response_ready=ax[i].responseText;
                  document.getElementById('return_table_'+i).innerHTML = response_ready;
              }
         } 
         ax[i].open("GET","av.pl?resolver=" + arr[i] +"&fqdn=google.com",true); //works 
         ax[i].send(null); //works 
      }

 }

1 Ответ

2 голосов
/ 01 января 2012

Ваша проблема чрезвычайно распространена. В JavaScript переменные находятся на уровне функций, а не на уровне операторов блока. Таким образом, когда вы повторяете этот цикл с переменной «i», каждая функция, которую вы создаете в цикле , разделяет то же самое «i». Таким образом, когда функции на самом деле называются , значение «i» будет таким, каким оно является в конце цикла & mdash; и это точка за концом массива!

Чтобы избежать этой проблемы, вам нужно создать эти функции в другой функции. Чистый способ сделать это - использовать отдельную локальную функцию:

 function makeReadyStateHandler(i) {
     return function() {
          if (ax[i].readyState != 4) {
               document.getElementById('return_table_'+i).innerHTML="loading "+i;
          }
          if(ax[i].readyState == 4){
              // get data from the server response
              var response_ready=ax[i].responseText;
              document.getElementById('return_table_'+i).innerHTML = response_ready;
          }
     };
 }

Затем просто вызовите эту функцию из цикла:

      ax[i].onreadystatechange = makeReadyStateHandler(i);

Используя такую ​​отдельную функцию, вы гарантируете, что каждая функция-обработчик будет иметь свою собственную копию «i», которая зафиксирована в правильной точке цикла. Функция вернет вновь созданную функцию в качестве результата, который вы будете использовать в качестве обработчика события.

...