Рекурсия и возврат Promise
Имеется следующий js-файлик:
$(document).ready(function() { $("#search_posts_by_groups_form2").submit(function(e){ e.preventDefault(); var groupArray = new Array(); var token = $('#token')[0].value; if (token.trim() == ""){alert('Введите Токен');return false;} var delim = $('#search_delim')[0].value; var groups_id = $('#search_groups')[0].value; // Получаем список сообществ var groups_arr = groups_id.split(delim); var groupsSize = groups_arr.length; var k = 0; var checkSum = 0; var groupIDArray = new Array(); $.each(groups_arr, function(i, group_id) { groupIDArray[k] = group_id; ++k; }); var dfd = initGroupInfo(token, groupArray, groupIDArray, 0); dfd.done(function(){ console.log('Закончили. Можно запускать другую функцию!') }); }); }); function initGroupInfo(token, groupArray, groupIDArray, currentGroupIDIndex){ var dfd = $.Deferred(); var group_id = groupIDArray[currentGroupIDIndex]; var promisedCalbackGroup = callbackGroup(token, group_id); promisedCalbackGroup.done( function(data){ var obj = data.response; if (obj){ if (obj[0]){ group_id = groupIDArray[currentGroupIDIndex]; groupArray[group_id] = new Object(); groupArray[group_id].group = obj[0]; console.log('Загрузка информации о группе: ' + group_id); if ( (groupIDArray.length - currentGroupIDIndex) > 1){ initGroupInfo(token, groupArray, groupIDArray, ++currentGroupIDIndex); }else{ console.log('Загрузка информации о группах завершена'); dfd.resolve(); } }else{ console.log('Ошибка: initGroupInfo(2)'); } }else{ console.log('Ошибка: initGroupInfo(1)'); } } ); return dfd.promise(); }; function callbackGroup(token, group_id){ return $.ajax({ url: 'https://api.vk.com/method/groups.getById?v=5.52&access_token=' + token + '&group_id=' + group_id, type: 'GET', async: true, dataType: 'jsonp', crossDomain: true }); }; Я пытаюсь вызвать асинхронные запросы последовательно. Имеется список групп. Необходимо последовательно вызвать ajax и обработать полученные результаты так, чтобы выполнение следующего ajax-запроса начиналось после завершения обработки выполнения результатов предыдущего запроса. Помимо этого я хочу отследить выполнение initGroupInfo, чтобы после него запустить другую функцию. Проблема в том, что у меня мало знаний по promise и deffered. Я не представляю, как правильно вызвать resolve и потому код не работает. Я гуглил, но те примеры, которые я встречал не имеют ничего общего с моей ситуацией. |
Цитата:
|
Цитата:
|
Цитата:
|
Если я правильно понял ваш код, то не хватает возврата результата dfd по всей цепочке рекурсии. И реджектов в случае ошибки:
if ( (groupIDArray.length - currentGroupIDIndex) > 1){ *!* dfd = */!* initGroupInfo(token, groupArray, groupIDArray, ++currentGroupIDIndex); }else{ console.log('Загрузка информации о группах завершена'); dfd.resolve(); } }else{ console.log('Ошибка: initGroupInfo(2)'); *!* dfd.reject(); */!* } }else{ console.log('Ошибка: initGroupInfo(1)'); *!* dfd.reject(); */!* } Ну и обработка ошибки: dfd.done(function(){ console.log('Закончили. Можно запускать другую функцию!') }) *!* .fail(function(){ */!* *!* console.log('ошибка'); */!* *!* }); */!* Хотя лучше бы вы выложили ваш пример на https://jsfiddle.net/ чтобы там можно было сразу проверить. |
Цитата:
Конечное сообщение после выполнения initGroupInfo не выходит. Мне кажется, в ходе рекурсии первый вызов не вызывает resolve. Т.е. deffered теряется и никогда не вызывается, а на последнем шаге он вызывается, но возвращается в предыдущий вызов, но там никакого обработчика нет. Написал вот так, но такой способ вернет ответ после первого вызова. Получается, надо как-то передавать предыдущий deffered. (Код ниже вернет результат после первого же вызова) function initGroupInfo(token, groupArray, groupIDArray, currentGroupIDIndex){ var dfd = $.Deferred(); var group_id = groupIDArray[currentGroupIDIndex]; var promisedCalbackGroup = callbackGroup(token, group_id); promisedCalbackGroup.done( function(data){ var obj = data.response; if (obj){ if (obj[0]){ group_id = groupIDArray[currentGroupIDIndex]; groupArray[group_id] = new Object(); groupArray[group_id].group = obj[0]; console.log('Загрузка информации о группе: ' + group_id); if ( (groupIDArray.length - currentGroupIDIndex) > 1){ var dfd1 = initGroupInfo(token, groupArray, groupIDArray, ++currentGroupIDIndex); dfd1.done( new function(){ dfd.resolve(); } ); }else{ console.log('Загрузка информации о группах завершена'); dfd.resolve(); } }else{ console.log('Ошибка: initGroupInfo(2)'); dfd.reject(); } }else{ console.log('Ошибка: initGroupInfo(1)'); dfd.reject(); } } ); return dfd.promise(); }; |
Цитата:
|
Цитата:
function initGroupInfo(token, groupArray, groupIDArray, currentGroupIDIndex *!* , dfd_out = false */!* ){ initGroupInfo(token, groupArray, groupIDArray, ++currentGroupIDIndex *!* , dfd */!* ); }else{ console.log('Загрузка информации о группах завершена'); if(dfd_out) *!* dfd_out.resolve(); */!* if(dfd_out) *!* dfd.done(function(){ dfd_out.resolve(); }); */!* return dfd.promise(); |
Цитата:
К сожалению, уже сил и желания нет сидеть с этим Deffered. Нашкодил массив из вызываемых функций и пихаю в функцию, которая управляет очередью. В вызываемых функциях после ajax-запроса устанавливаются управляющие флаги и вызывается функция управления очередью, которая по полученным флагам принимает решение: запустить очередную итерацию или переходить к следующей функции. В конечном счете я добился своего: создается иллюзия, будто запустил скрипт последовательно. Нашкодил много, что выкладывать подобное даже не хочется. За трату своего времени всем спасибо. В репутации отмечу. |
Часовой пояс GMT +3, время: 03:09. |