2009-08-13 4 views
1

В такой ситуации, как приведенный ниже код, как вы можете получить доступ к переменной, которая находится в анонимной функции? Я хотел бы вернуть значение bool filterData (xmlhttp.responseText, thisForm); который будет иметь значение boolean для основной функции checkAvailable. Заранее спасибо.Javascript, ссылка на переменную

function checkAvailable(thisForm) { 

    var xmlhttp = httpRequest(); 
    var isValid = true; 
    var un = document.getElementById('u_username').value; 
    var email = document.getElementById('u_email').value; 

    xmlhttp.onreadystatechange = function(isValid) { 
     if (xmlhttp.readyState == 4) { 
       //I WANT TO ACCESS THIS isValid VARIABLE FROM MAIN FUNCTION checkAvailable 
       isValid = filterData(xmlhttp.responseText, thisForm); 
     } 
    } 

    xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true); 
    xmlhttp.send(null); 

    return isValid; 
} 

так, как я теперь

function validateRegForm(thisForm) { 

    var isValid = true; 
    var warningIcon = "";//for later in case we want to use an icon next to warning msg 

    checkAvailable(thisForm, function(isValid) { });   

    if(isValid == false) 
     window.scroll(0,0); 

    alert(isValid); 

    return false;//isValidForm; 
} 


function checkAvailable(thisForm, resultFunction) { 

     var xmlhttp = httpRequest(); 
     var un = document.getElementById('u_username').value; 
     var email = document.getElementById('u_email').value; 

     xmlhttp.onreadystatechange = function(isValid) { 
      if(xmlhttp.readyState == 4) { 
       isValid = filterData(xmlhttp.responseText, thisForm); 
       resultFunction(isValid); 
      } 
     } 
      xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true); 
    xmlhttp.send(null); 
} 

ответ

5

Изменить checkAvailable функции, чтобы взять дополнительный параметр, который является функцией вызовите результат.

function checkAvailable(thisForm, resultFunction) { 
    .. 
    xmlhttp.onreadystatechange = function(isValid) { 
    if (xmlhttp.readyState == 4) { 
     //I WANT TO ACCESS THIS isValid VARIABLE FROM MAIN FUNCTION checkAvailable 
     isValid = filterData(xmlhttp.responseText, thisForm); 
     resultFunction(isValid); 
    } 
    } 
} 

Затем, вы можете назвать это что-то вроде этого:

checkAvailable(thisForm, function(isValid) { 
    // Use the isValid value which is the result of the checkAvailable call. 
}); 

EDIT Вот изменения в модифицированном коде, публикуемую.

function validateRegForm(thisForm) { 
    var isValid = true; 
    var warningIcon = "";//for later in case we want to use an icon next to warning msg 

    checkAvailable(thisForm, function(isValid) { 
    if(isValid == false) 
     window.scroll(0,0); 

    alert(isValid); 
    } 

    // WARNING!! This will happen before the result is discovered. 
    // You'll need to modify the function that called into validateRegForm. 
    // It should not wait for a return parameter either. 
    return false;//isValidForm; 
} 
+1

быстрые пальцы г-н Фишер;) - удаление моего обманутого ответа и добавление заметки к вашему: любые асинхронные вызовы должны обрабатываться с обратными вызовами вместо возвращаемых значений – gnarf

+1

+1 для использования обратного вызова вместо синхронного ввода-вывода, а также для выполнения это правильно. Ответы gnarf и jvenema вызывают вызов функции Function вне блока if(), который, вероятно, не тот, который вы хотите.Вероятно, вы хотите только вызвать обратный вызов при xmlhttp.readyState == 4, потому что в противном случае вы получите ложные обратные вызовы для других изменений readyState. (В Gecko вы можете получить произвольно большое количество обратных вызовов, если у вас большой или медленный ответ, IIRC.) –

+0

Я на самом деле отредактировал мой, чтобы поместить resultFunc-вызов внутри if, прежде чем я заметил, что ответ Джона побил меня в любом случае , только одно примечание, что funciton (isValid) излишне отображает прочь от значения var isValid, определенного выше. должен быть просто функцией() { – gnarf

1

Вы должны сделать свой XmlHttpRequest синхронно, вы можете сделать это, установив последний параметр .Open() к ложным, т.е.

xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",false); 

Однако это заблокирует ваш UI/SJS в течение всего времени звонка

+0

Хотя действительный ответ - я не думаю, что вы хотите, чтобы принять этот совет - Синхронные вызовы могут быть более понятным, но методы обратного вызова гораздо безопаснее и не блокируют javascript - не предупреждают о том, что слишком долго - и т. д. – gnarf

0

Если вам нужно подождать Чтобы продолжить, используйте SJAX (синхронный javascript и xml), чтобы получить результат. Ваш скрипт не будет продолжаться, пока вы не получите ответ. Остерегайтесь того, что ошибки тайм-аута обрабатываются неточно.

С другой стороны, вы можете использовать AJAX и делать то, что вам нужно сделать в проверке readyState, вместо того, чтобы пытаться вернуть значение для чего-то еще, чтобы обработать его.

0

В качестве третьего параметра необходимо ввести false в xmlhttp.open(). Это заставит запрос выполнить синхронно, и выполнение вашей программы приостановится до тех пор, пока оно не завершится.

Если вы сделаете это, вам не понадобится анонимная функция. Вы можете просто получить xmlhttp.responseText непосредственно:

function checkAvailable(thisForm) { 

    var xmlhttp = httpRequest(); 
    var isValid = true; 
    var un = document.getElementById('u_username').value; 
    var email = document.getElementById('u_email').value; 

    xmlhttp.open("GET", your_parameters, false); 
    xmlhttp.send(null); 
    isValid = filterData(xmlhttp.responseText, thisForm); 

    return isValid; 
} 

Основной недостаток состоит в том, что браузер будет в основном заморозить до завершения xmlhttp.send() вызова.

Если вы можете реорганизовать свой код, чтобы синхронный вызов не нужен, это было бы лучше ИМО.

+0

Спасибо за предложение, я пробовал это, и он работал, но я скорее использовал async. – Erik

0

Создание объекта вне функции ...

obj = new Object; 
obj.isValid = false; 
obj.complete = false; 

Тогда ваш код ... кроме

obj.isValid = filterData(xmlhttp.responseText, thisForm); 
objt.complete = true; 

Убедитесь, определение объекта выше функции, так что кажется, глобальный характер.

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

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

-1

Cheat: сделать данные обработчика запроса ajax в скрытом элементе. Затем ваша функция запроса (я предполагаю) может посмотреть на скрытый элемент, чтобы убедиться, что наконец установлен флаг «ready».

+0

-1 для предложения с использованием скрытого элемента, когда простая переменная будет делать то же самое. –

+0

Спасибо, сэр, может быть, у меня есть еще один! Да, он грязный и по-прежнему глобальный, но я предполагаю, что у меня есть предвзятость против (нелокальных) переменных javascript. – Roboprog

1

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

Например:

function a() { 
    var x = 1; 
    (function() { x = 2; })(); 
    alert(x); // x will be 2 
} 

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

function checkAvailable(thisForm) { 

    var xmlhttp = httpRequest(); 
    var isValid = true; 
    var un = document.getElementById('u_username').value; 
    var email = document.getElementById('u_email').value; 

    xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",false); 
    xmlhttp.send(null); 

    isValid = filterData(xmlhttp.responseText, thisForm); 

    return isValid; 
} 

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

function whenAvailable(theForm, callback) { 
    var xmlhttp = httpRequest(); 
    var un = document.getElementById('u_username').value; 
    var email = document.getElementById('u_email').value; 

    xmlhttp.onreadystatechange = function() { 
     if (xmlhttp.readyState === 4) { 
      if (callback) { 
       var isValid = filterData(xmlhttp.responseText, thisForm); 
       callback.call(null, isValid); 
      } 
     }   
    } 

    xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true); 
    xmlhttp.send(null); 

} 

Вызов этой функции будет выглядеть следующим образом:

whenAvailable(document.getElementById('someForm'), function(valid) { 
    if (valid) { 
     // do something when valid 
    } else { 
     // do soemthing when invalid 
    } 
}); 
0

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

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

функции checkAvailable (thisForm, обратный вызов) {

var xmlhttp = httpRequest(); 
var isValid = true; 
var un = document.getElementById('u_username').value; 
var email = document.getElementById('u_email').value; 

xmlhttp.onreadystatechange = function(isValid) { 
    if (xmlhttp.readyState == 4) { 
      //I WANT TO ACCESS THIS isValid VARIABLE FROM MAIN FUNCTION checkAvailable 
      isValid = filterData(xmlhttp.responseText, thisForm); 
    } 
    callback(isValid); 
} 

xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+un+"&email="+email+"",true); 
xmlhttp.send(null); 

}

Смежные вопросы