Область видимости переменных с deferred/ajax в jQuery

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

Мое ограниченное понимание области действия переменных и обратных вызовов при использовании асинхронного чего-либо и попытке выяснить отложенные jQuery причиняет боль моему слабому мозгу.

$('<div>')
.on({
    click : function(){
        console.log(
            fetchMyData() // this will be 'undefined' but why?
        )
    }
})

function fetchMyData(){
    $.ajax({
        // ajax setup
    })
    .done(function(response){
        console.log( response ); // shows 'hello' as expected
        return response; 
    })
}

Я понимаю, что вызов ajax не обязательно будет выполнен к тому времени, когда я выполняю console.log(), поскольку он, конечно, асинхронный.

Итак, как я могу сделать так, чтобы fetchMyData() отображал результат ajax, как только он будет готов?


person tim    schedule 16.07.2013    source источник
comment
Что ты пытаешься сделать? fetchMyData() регистрируется как undefined, потому что ничего не возвращает. Есть ли причина, по которой вы избегаете .done()?   -  person Dallas    schedule 17.07.2013
comment
Возврат чего-либо внутри обратного вызова done фактически ничего не делает. Вы можете использовать return $.ajax({... в своей функции fetchMyData. Затем в обработчике кликов используйте fetchMyData.done(function() { console.log("foo"); });   -  person Ian    schedule 17.07.2013
comment
поместите код, который отображает результат, где в настоящее время находится ваш оператор return...   -  person dandavis    schedule 17.07.2013


Ответы (3)


Вы можете использовать jQuery, когда так:

$('<div>')
    .on({
        click : function() {

           $.when(fetchMyData()).then(function(data) {
                    console.log(data);
           });
         }
    });

    function fetchMyData(){
        return $.ajax({
            // ajax setup
        });
    }
person L105    schedule 16.07.2013
comment
Это интересно. Но теперь мне нужно выполнить настройку в обработчике кликов. Должен быть способ имитировать синхронное поведение, чтобы я мог просто написать console.log( fetchMyData() ); - person tim; 17.07.2013

Вы должны изменить то, что делает функция fetchMyData. Попробуйте вернуть объект обещания.

$('<div>').click(function()
{

    var fetchMyDataPromise  = fetchMyData() ;

    fetchMyDataPromise.done(function(response)
    {
        console.log(response);
    });

});

function fetchMyData()
{
    return  $.ajax({ // ajax setup });
}  
person Tomas Santos    schedule 16.07.2013

Итак, как я могу сделать так, чтобы fetchMyData() отображал результат ajax, как только он будет готов?

Вы уже сделали это в обратном вызове .done. Если вы хотите, чтобы fetchMyData возвращал ответ, вы должны использовать синхронный вызов, что обычно нецелесообразно (поскольку пользовательский интерфейс зависнет до получения ответа).


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

function fetchMyData(thenDoThis){
    $.ajax({
        // ajax setup
    }).done(thenDoThis)
}

function doSomethingWithResponse(response) {
    // do something
}

Затем назовите это так:

fetchMyData(doSomethingWithResponse);

Или вот так:

$('<div>').click(function() {
    fetchMyData(function(response){
        console.log(response);
    });
});
person bfavaretto    schedule 16.07.2013
comment
Благодарю. Вот что я думал. Любой способ избежать обратных вызовов? Потому что мне кажется, что это слишком сложный код. @L105 говорит о .when(), что звучит интригующе - person tim; 17.07.2013
comment
Другие предложения (от L105 и Томаса Сантоса) подразумевают, что вы передаете функцию, которая будет вызываться при получении ответа, так что это просто другой синтаксис для обратных вызовов (на основе промисов, что действительно очень интересно). Это не слишком сложно, это стандартный способ работы с асинхронными операциями. Единственный способ избежать этого — использовать синхронный запрос, что, как я уже говорил, нехорошо... - person bfavaretto; 17.07.2013
comment
да, я долго боролся с этим, используя async:false, и, наконец, признал, что это просто напрашивается на неприятности. Я не рекомендую использовать синхронный AJAX, он же SJAX - person tim; 17.07.2013