Правильный способ ожидания возврата ajax (я не хочу использовать обработчик успеха).

Возможный дубликат:
Как я могу получить jQuery для выполнения синхронного, а не асинхронного запроса AJAX?
как ждать возвращения ajax-запроса

Услышьте меня. Я полностью понимаю этот сегмент кода.

$.getJSON(someURL, function(data){
    //do something with my data
})
.success(function () {
    //Call what you want on success
})

Это кажется прекрасным, если мне просто нужно сделать одно действие, которое довольно статично. Однако, если я хочу быть менее ограниченным, например, это

function my_func(){
    $.getJSON(someURL, function(data){
        //do something with my data... like modify an array or the dom
    })
}

Теперь драйвер

my_func();
//Now I want to call a function that relies on the data that my_func brought into the script.

Что-то не так с тем, как я кодирую свой script, если я хочу сделать это вот так? Или я просто пропустил какой-то потрясающий встроенный метод?

Ответ 1

Я вижу два возможных пути jQuery-ish.

Первым будет использование другого обратного вызова, который может быть передан в my_func:

function my_func(callback) {
    $.getJSON(someUrl, function(data) {
        // ...do stuff ...
        if ($.isFunction(callback)) { callback(data); }
    });
}

my_func(function(data) {
    // ..do more stuff..
});

Второй способ - создать настраиваемое событие, которое запускается внутри my_func, и его можно прослушивать извне:

function my_func() {
    $.getJSON(someUrl, function(data) {
        $(document).triggerHandler('my_func:data-received', [data]);
    });
}

$(document).on('my_func:data-received', function(event, data) {
    // ...do stuff...
});

my_func();

Я настоятельно рекомендую использовать async: false только в том случае, если это абсолютно необходимо.


Еще один (очень аккуратный) способ справиться с этим - это объект jQuery.Deferred:

function my_func() {
    var d = new $.Deferred();
    $.getJSON(someUrl, function(data) {
        d.resolve(data);
    });
    return d;
}

my_func().done(function(data) {
    // ...do stuff...
});

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

Ответ 2

Тогда есть объект XHR:

var jqXHR = $.getJSON(someURL);

Вы можете получить к нему доступ в любом месте после его определения:

jqXHR.always(function() {
    alert('JSON IS COMLETE');
});

jqXHR.done(function(data) {
    //do something with the returned data if success!
});

jqXHR.fail(function(jqXHR, textStatus) {
    alert('JSON FAILED : '+textStatus);
});

FIDDLE

Вы можете даже сделать что-то вроде этого:

$("#button").on('click', Myfunc);

function Myfunc() {
    var jqXHR = runAjax();
        jqXHR.done(function(data) {
            alert($.parseJSON(data));
            $("#result").html('JSON IS DONE');
        });
}

function runAjax() {
    return $.getJSON(someURL);
}

FIDDLE

Ответ 3

Вероятно, вы передадите свою функцию, которая работает с данными, в my_func().

 //                    v--------receive a callback
function my_func(callback_fn){

    $.getJSON(someURL, callback_fn); // use the callback as the getJSON callback

}

то...

my_func(function(data) {
    // do something with data
})

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

my_func(someOtherFunction)

В любом случае ваша функция my_func() будет использовать ее в качестве обратного вызова к вызову $.getJSON, который будет вызывать его при поступлении данных.