Как я могу избежать проанализированных данных из функции XHR? - PullRequest
0 голосов
/ 25 февраля 2012

Мой вопрос, по сути, заключается в том, что я пытаюсь сделать универсальную функцию Ajax исключительно для получения информации, которая будет проанализирована и затем автоматически сохранена как значение того, что ее вызвало. В данном конкретном случае это гигантский словарный список слов для игры палача, которую я делаю. Как я могу избежать массива, созданного ajaxRequest.responseText.split("\n") во все, что его вызывает. В моем случае это будет ALAMI.Hangman.Wordlist

Моя конечная цель - использовать ALAMI.Hangman.Wordlist[i] и заставить его возвращать значение любой строки, хранящейся в этом месте в массиве.

Прежде чем вы начнете волноваться, это не весь мой код, функция запроса XHR вызывается через ALAMI.XHR();, как написано ниже, но я не включил ее в этот код, потому что чувствовал, что это не нужно.

ALAMI.XHR.Get = function(URL){
  "use strict";
  var ajaxRequest = ALAMI.XHR();
  var ajaxResponse;

  ajaxRequest.open("GET", URL, true);
  ajaxRequest.send(null);
  ajaxRequest.onreadystatechange = function(){
    if(ajaxRequest.readyState === 4){
      ajaxResponse = ajaxRequest.responseText.split("\n");
      var extensionLocation = URL.lastIndexOf('.');
      console.log(URL.substr(extensionLocation) + " file ...... " + ajaxResponse.length + " lines.");
    }
  }
  return ajaxResponse;
}

ALAMI.Hangman = ALAMI.Hangman || {};

ALAMI.Hangman.Wordlist = ALAMI.XHR.Get('fulldictionary.txt');

//I want ALAMI.Hangman.Wordlist to be equal to the Array of ajaxRequest.responseText.split("\n")

Моя конечная цель - использовать ALAMI.Hangman.Wordlist[i] и заставить его возвращать значение любой строки, хранящейся в этом месте в массиве.

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

 ALAMI.Hangman.Wordlist1 = ALAMI.XHR.Get('fulldictionary.txt');
 ALAMI.Hangman.Wordlist2 = ALAMI.XHR.Get('dictionary2.txt');

Конечная цель:

Если в глобальном пространстве я пишу console.log(ALAMI.Hangman.Wordlist[0]);, он в настоящее время отображается как неопределенный, однако, я хочу, чтобы массив хранился в ALAMI.Hangman.Wordlist, чтобы при выполнении этого он выводил первое значение массив.

console.log(ALAMI.Hangman.Wordlist[0]); //Should output Apple

Ответы [ 4 ]

1 голос
/ 25 февраля 2012

Итак, вы хотите создать объект WordList, а затем передать его вокруг остальной части вашей программы, не вызывая необязательно Ajax-запрос до тех пор, пока к WordList не будет получен доступ?

Вы столкнулись с проблемами, потому что без использования обратных вызовов остальныевашего кода пытается оценить WordList до того, как будет выполнен запрос AJAX, фактически, даже если запрос был заполнен, браузер ожидает завершения вашего текущего «цикла» кода, прежде чем он выполнит обратный вызов readystatechange для заполнения вашего списка.Вы можете использовать синхронизирующий вызов AJAX, или я, вероятно, переписал бы вашу функцию XHR следующим образом:

function wordlist(url,withwords) {
    var xhr = // create your xhr object;
    xhr.onload = function (data) {
        withwords(parsetolist(data));
    }
    xhr.send()
}

wordlist('dict1.txt', function(words) {
    // pass words around to other functions
    filterwords(words);
    randomizewords(words);
    // or use it here
    console.log(words[2]);
}

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

function wordlist2(url) {
    var evaluated = false;
    var response = function (index, withword) {
        if ( evaluated ) { withword(evaluated[index]); }
        else {
            wordlist(url, function(words) {
                 evaluated = words;
                 withword(words[index]);
            })
        }
    }
    return response;
}
ALAMI.WORDLIST = wordlist2('dict1.txt');
ALAMI.WORDLIST(2,function (word) { console.log(word); });
1 голос
/ 26 февраля 2012

проблема в том, как вы используете объект XMLHttpRequest (). Поскольку вы указали true в ajaxRequest.open("GET", URL, true);, вы фактически запрашиваете, чтобы запрос был выполнен в асинхронном потоке, чтобы основной поток не блокировался. Это хороший дизайн для приложений HTML, но он требует от вас лучшего понимания того, как лучше обрабатывать результаты, возьмем следующий пример:

<html>
<head>
<title>ALAMI Test</title>
<script language="JavaScript">
function doit(URL) {
  console.log('mainthread - doit begin');
  var ajaxRequest = new XMLHttpRequest();
  ajaxRequest.open("GET", URL, true);
  ajaxRequest.onreadystatechange = function() {
    if (ajaxRequest.readyState === 4) {
      console.log('asyncthread - readystatechange begin');
      var ajaxResponse = ajaxRequest.responseText.split("\n");
      var extensionLocation = URL.lastIndexOf('.');
      console.log('asyncthread - readystatechange end');
    }
  }
  console.log('mainthread - ajaxRequest.send');
  ajaxRequest.send(null);
  console.log('manthread - doit end');
}
</script>
</head>
<body>
<input type="button" value="doit" onclick="doit('http://localhost/fulldictionary.txt')"/>
</body>

Обратите внимание на места, где я отметил console.log и которые находятся в mainthread и которые находятся в asyncthread . Если вы должны запустить скрипт, вы должны увидеть следующий текст в консоли:

LOG: mainthread - doit begin 
LOG: mainthread - ajaxRequest.send 
LOG: manthread - doit end 
LOG: asyncthread - readystatechange begin 
LOG: asyncthread - readystatechange end 

То, как вы написали свой сценарий, вы предполагали, что результаты происходят синхронно, т.е.

LOG: mainthread - doit begin 
LOG: mainthread - ajaxRequest.send 
LOG: asyncthread - readystatechange begin 
LOG: asyncthread - readystatechange end 
LOG: manthread - doit end 

именно поэтому ваш скрипт не работает. Правильный дизайн - продолжать работать с асинхронной нитью, но использовать ее для «обратной отправки» записей, найденных в вашем объекте ALAMI. Таким образом, вы не можете использовать следующую строку кода:

ALAMI.Hangman.Wordlist = ALAMI.XHR.Get('fulldictionary.txt');

Поскольку, когда основная тема завершается, список слов все еще неизвестен, вместо этого вы должны переписать его следующим образом:

ALAMI.XHR.Get('fulldictionary.txt');

И в рамках реализации вашего асинхронного потока вы должны сделать так, чтобы он заполнял ваш список слов.

т.е. требуется редизайн.

1 голос
/ 25 февраля 2012

[ отредактировано на основе комментария ]

Если вы хотите заполнить ALAMI.Hangman.Wordlist из результата запроса XHR, вы должны сделать это в обратном вызове этого запроса

ALAMI.Hangman = ALAMI.Hangman || {};

//change ALAMI.XHR.Get = function(URL) to
//       ALAMI.XHR.Get = function(URL,listID)

ALAMI.XHR.Get('fulldictionary.txt','WordList');
ALAMI.XHR.Get('fulldictionary2.txt','WordList2');
ALAMI.XHR.Get('fulldictionary3.txt','WordList3');

// [...]
  ajaxRequest.onreadystatechange = function(){
    if(ajaxRequest.readyState === 4){
      ajaxResponse = ajaxRequest.responseText.split("\n");
      var extensionLocation = URL.lastIndexOf('.');
      ALAMI.Hangman[listID]  = ajaxResponse; // <===
      // [...]
      // do stuff with the populated ALAMI.Hangman[listID]
    }
  }
0 голосов
/ 26 февраля 2012

Спасибо всем, кто помог мне ответить на этот вопрос! Однако все приведенные ответы содержали полезную информацию, чтобы помочь ответить на вопрос, поскольку ни в одном ответе не содержалось все понимание, необходимое для решения моей проблемы, и я публикую ответ.

Решение выглядит следующим образом:

  1. Мне нужно было использовать функцию обратного вызова .
  2. Функция обратного вызова должна выполняться только после того, как запрос XHR был выполнен.

    -Это особенно важно и имеет отношение к тому факту, что мы используем асинхронный AJAX.

  3. Мне нужно было убедиться, что ALAMI.Hangman.Wordlist установлено равным соответствующему значению ajaxResponse, а не ALAMI.XHR.Get().

Код, который я придумал, выглядит следующим образом.

ALAMI.XHR.Get = function(URL, callback){ //callback argument was added
  "use strict";
  var ajaxRequest = ALAMI.XHR();
  var ajaxResponse;

  ajaxRequest.open("GET", URL, true);
  ajaxRequest.send(null);
  ajaxRequest.onreadystatechange = function(){
    if(ajaxRequest.readyState === 4){
      ajaxResponse = ajaxRequest.responseText.split("\n");
      var extensionLocation = URL.lastIndexOf('.');
      console.log(URL.substr(extensionLocation) + " file, " + ajaxResponse.length + " lines");
      if(callback){
        callback(ajaxResponse); //callback is called after URL is parsed into an Array
      }
    }
  }
}

ALAMI.Hangman = ALAMI.Hangman || {};
ALAMI.Hangman.Wordlist;

ALAMI.XHR.Get('fulldictionary.txt', function(aR){ //callback function is specified
  ALAMI.Hangman.Wordlist = aR;                    //assigning the Wordlist property now works!
  console.log('Wordlist Retrieved');
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...