1

Я знаю, здесь уже много вопросов об AJAX и синхронности, но я почему-то не нашел правильного ответа на мое дело. Пожалуйста, будьте осторожны, я ноб, так что это может быть дубликат. Тем не менее, даже намек на это может помочь мне и другим найти правильный ответ.Несколько вложенных вызовов AJAX в jQuery: как это сделать правильно, не возвращаясь к синхронному?

Функция

$.fn.facebookEvents = function(options){ 
    var fbEvents = 'https://graph.facebook.com/'+options.id+'/events/?access_token='+options.access_token+'&since=now&limit=500'; 
    var events = []; 

    $.when($.getJSON(fbEvents)).then(function(json){ 

     $.each(json.data, function(){ 
      $.getJSON('https://graph.facebook.com/'+this.id+'/?access_token='+options.access_token, function(jsonData){ 
       events.push(jsonData); 
       console.log(events);   // here array "events" is filled successively 
      }); 
       console.log(events);   // here array "events" remains empty 
     }); 

    }).done(function(){ 

     $("#fb_data_live").html(
      $("#fb_events").render(events) 
     ); 

    }); 
}; 

Что происходит в этой функции является AJAX вызовов (через jQuerys getJSON стенографии) для списка событий на странице Facebook. Это вернет список объектов JSON, представляющих каждую дату. Пример одного объекта в качестве ответа:

{ 
    "end_time": "2017-03-16T23:00:00+0100", 
    "location": "Yuca K\u00f6ln", 
    "name": "K\u00f6rner // G\u00e4nsehaut Tour 2017 // K\u00f6ln", 
    "start_time": "2017-03-16T20:00:00+0100", 
    "timezone": "Europe/Berlin", 
    "id": "985939951529300" 
}, 

К сожалению, эти данные не имеют необходимой информации. Они скрыты (вложены) и могут быть найдены после создания второго getJSON (строка 8 в функции) с использованием индивидуального «id» каждого объекта. В настоящее время Facebook отвечает:

{ 
    "description": "http://www.eventim.de/koerner\nTickets ab sofort exklusiv auf eventim.de und ab MI 07.09. \u00fcberall wo es Tickets gibt sowie auf contrapromotion.com.", 
    "end_time": "2017-03-16T23:00:00+0100", 
    "is_date_only": false, 
    "location": "Yuca K\u00f6ln", 
    "name": "K\u00f6rner // G\u00e4nsehaut Tour 2017 // K\u00f6ln", 
    "owner": { 
     "name": "K\u00f6rner", 
     "category": "Musician/Band", 
     "id": "366592010215263" 
    }, 
    "privacy": "OPEN", 
    "start_time": "2017-03-16T20:00:00+0100", 
    "timezone": "Europe/Berlin", 
    "updated_time": "2016-09-28T10:31:47+0000", 
    "venue": { 
     "name": "Yuca K\u00f6ln" 
    }, 
    "id": "985939951529300" 
} 

Et voila, подробности, которые я искал. После выполнения этого второго (вложенного) вызова AJAX я выталкиваю данные JSON в массиве «события» (строка 12).

Проблема

Это должно заполнить массив с каждой итерации .each. Однако взгляните на два «console.logs». Первый возвращает заполненный массив, второй возвращает пустой массив ... Если вызовы AJAX выполняются синхронно (что не так, как должно быть), например. добавив $.ajaxSetup({async: false}); до функции, он работает отлично. Массив заполняется и может быть отображен (строка 18).

Вопрос

Как это поведение можно объяснить и как эта функция может быть сделано правильно? Я знаю, должен быть способ использовать отложенные и обещания? Я думал, что сделал, используя .если тогда ... я ... я ошибся.

С наилучшими пожеланиями, Джулиуса

ответ

1

Очевидно вы не знаете ничего о обещаниях. Думаю, я сделал бы это по-другому, но используя обещания, вы могли бы сделать следующее:

$.fn.facebookEvents = function(options){ 
    var fbEvents = 'https://graph.facebook.com/'+options.id+'/events/?access_token='+options.access_token+'&since=now&limit=500'; 
    var events = []; 
    var deferred=$.Deferred(); 
    var promises=[]; 
    var done=false; 

    $.when(deferred).then(function(events) { 
     console.log(events); 
    }); 

    $.getJSON(fbEvents).done(function(json){ 
     $.each(json.data, function(){ 
      promises.push($.getJSON('https://graph.facebook.com/'+this.id+'/?access_token='+options.access_token).done(function(jsonData){ 
       events.push(jsonData); 
       var completed=promises.filter(function(element) { return element.state=='pending' }).length==0; 
       if(done&&completed) { 
        deferred.resolve(events); 
       } 
      })); 
     }); 
     done=true; 
    }); 
}; 
0

спасибо за ваш ответ. Для полноты я придумал альтернативное решение.

$.fn.facebookEvents = function(options){ 
    var fbEvents = 'https://graph.facebook.com/'+options.id+'/events/?access_token='+options.access_token+'&since=now&limit=500'; 
    var events = []; 
    var eventsData = []; 
    var i; 

    // first call 
    function A() { 
     return $.getJSON(fbEvents).then(function(json){ 
      events.push(json); 
      i = events[0].data.length; 
     }); 
    }; 

    // second call for objects details 
    function B(resultFromA) { 
     $.each(events[0].data, function(){ 
      $.getJSON('https://graph.facebook.com/'+this.id+'/?access_token='+options.access_token, function(jsonData){     
       eventsData.push(jsonData); 
       i--; 

       if (i == 0){ 
        output(eventsData); 
       }; 
      }); 
     }); 
    }; 

    A().then(B); 

    function output() { 
     //render here 
    }; 

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