путаница в возвращаемом значении функции javascript

#javascript #ajax

#javascript #ajax

Вопрос:

Мне неясно возвращаемое значение следующего фиктивного кода:

 function foo()
  var ret = 0;
  var xhr=send_request( "bla", function() {
      // do something with the AJAX response
      // based on the value of response, var ret get set
  } );
  return ret;
}
  

Чего я хотел бы добиться, так это того, что: основываясь на ответе AJAX, я мог бы решить повторить запрос еще раз. Но функция, описанная выше, всегда возвращает 0 независимо.

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

Спасибо

Комментарии:

1. К чему foo возвращается? К этому можно получить доступ внутри send_request ?

2. ваша функция обратного вызова ajax вызывается асинхронно, поэтому ret никогда не будет установлен на что-то другое. область действия неназванной функции находится не в foo(), а локально.

Ответ №1:

Вы пытаетесь выполнить вызов ajax синхронно, но вы выполняете асинхронный вызов.

Важно понимать, что в соответствии с тем, как вы это написали, код не ожидает завершения вызова AJAX, прежде чем перейти к следующей строке. Следовательно, она всегда возвращает начальное значение ret .

Сделайте несколько вещей, чтобы исправить это:

  • Используйте jQuery (если вы еще этого не сделали)
  • Используйте ajax() функцию jQuery и установите async значение false.

Должно выглядеть примерно так:

 function foo()
    var ret = $.ajax({ url: "blah",
                       async: false
                     }).responseText;

    // do your stuff here

    return ret;
}
  

РЕДАКТИРОВАТЬ: Это можно сделать с помощью асинхронного вызова, но вам нужно изменить способ, которым вы думаете о проблеме. Вместо того, чтобы думать о возвращаемых значениях, вы должны думать о функциях обратного вызова.

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

 function GetUsername() {
    $.ajax( { url: "blah",
              success: PopulateUsername    // Specify a callback
            });
    // I don't do anything else. Execution will continue when the
    // callback gets called from the AJAX call.
}

function PopulateUsername(data) {
    alert(data);
    // Anything else I want to do, I do here, because it is only 
    // here that I have access to the result.
}

GetUsername();  // I call GetUsername() here, and that's it. Any
                // further actions that need to happen are going to
                // occur in the callback function
  

Комментарии:

1. Спасибо. Есть ли какой-либо другой способ, кроме синхронизации запроса AJAX?

2. Да, но это требует рефакторинга вашего кода (и корректировки вашего образа мышления о вещах). Я внесу небольшую правку.

3. Использование document.write в примере не так уж и здорово, особенно потому, что полное DOM-дерево будет уничтожено по завершении Ajax-запроса.

4. @Marcel Korpel, изменено. Это была наименее важная строка во всем примере.

5. Я знаю, но всегда есть копирайтеры, которые возвращаются и задают вопросы типа «Почему вся страница удалена после моего запроса Ajax?».

Ответ №2:

переменная ret имеет локальную область видимости внутри функции. Следовательно, при каждом ее вызове переменная инициализируется значением 0.

Более того, когда функция возвращает переменную, ret send_request функция (которая установила что-то другое на ret ) еще не запущена, из-за чего возвращаемое значение всегда равно 0. Запрос ajax должен быть выполнен после того, как функция была возвращена, и send_request функция установила новое значение в ret .

Ответ №3:

Если вы хотите сохранить синхронность, воспользуйтесь предложением Stargazer712.

Вы могли бы попробовать сохранить асинхронность с чем-то вроде этого:

 function foo(callback)
  var xhr=send_request( "bla", function(result) {
     callback(result)
  } );
}


function test(result) {
  // test result here 
  if(result != "what I want")
     foo(test);   // repeat the ajax call under certain conditions
  else
     alert("got it");
}


$(function() {
  foo(test);
});
  

Запрос ajax будет повторяться до тех пор, пока ответ не будет соответствовать определенному значению.

Комментарии:

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

2. Да, это не для слабонервных 🙂

Ответ №4:

Вы не хотите возвращать значение из функции, которая собирается выполнить вызов AJAX, потому что запрос AJAX не будет завершен до возврата функции (и лично я не согласен с ответами, в которых говорится, что вы должны установить для async значение false). Вместо этого вы хотите сделать что-то подобное:

 function retFunction(val) {
  // Do something here for various values of val
  if (val == 0) {
    // Something
  } else if (val == 1) {
    // Something else
  }
}

function foo()
  var xhr=send_request( "bla", function() {
    var myResult = 0; // Something here based on return values.
    retFunction(myResult);
  });
}