Рекурсия и возврат 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 и потому код не работает. Я гуглил, но те примеры, которые я встречал не имеют ничего общего с моей ситуацией. |
koha345,
Одной темы мало что-ли надо три создать? |
Цитата:
|
koha345,
А должно быть так: одна задача = одна тема, и в этой теме обсуждаешь свои проблемы по задаче. |
Цитата:
|
Цитата:
|
Цитата:
|
Если я правильно понял ваш код, то не хватает возврата результата 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/ чтобы там можно было сразу проверить. |
koha345,
Такой итератор: function iterator(array) { var index = 0, cycle = 0; return { next: function () { if (index >= array.length) index = 0, cycle++; return { cycle: cycle, index: index, value: array[index++] } } } } var groups = ['a', 'b', 'c']; var iterable = iterator(groups); for (var i = 6; i--;) console.log(iterable.next()); // test Как можно использовать: function request(current) { $.ajax({ complete: function (jqXHR, textStatus) { if (current.cycle < 2) { if (current.cycle == 0) { console.log('task 0', current.value, current.index); } if (current.cycle == 1) { console.log('task 1', current.value, current.index); } request(iterable.next()); } else { console.log('no tasks'); } } }); } request(iterable.next()); UPD: точнее так (в общем думаю смысл понятен): function request(current) { if (current.cycle < 2) { $.ajax({ complete: function (jqXHR, textStatus) { if (current.cycle == 0) { console.log('task 0', current.value, current.index); } if (current.cycle == 1) { console.log('task 1', current.value, current.index); } request(iterable.next()); } }); } else { console.log('no tasks'); } } request(iterable.next()); |
Цитата:
Конечное сообщение после выполнения 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(); }; |
Часовой пояс GMT +3, время: 01:24. |