08.08.2017, 19:52
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Рекурсия и возврат 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 и потому код не работает. Я гуглил, но те примеры, которые я встречал не имеют ничего общего с моей ситуацией.
|
|
08.08.2017, 21:42
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Сообщение от Rise
|
koha345,
Одной темы мало что-ли надо три создать?
|
одна проблема = одна тема.
|
|
08.08.2017, 22:02
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Сообщение от Rise
|
koha345,
А должно быть так: одна задача = одна тема, и в этой теме обсуждаешь свои проблемы по задаче.
|
Договорились.
|
|
09.08.2017, 20:19
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Сообщение от Rise
|
А до этого какая функция была?
|
initGroupInfo
|
|
09.08.2017, 23:48
|
|
Профессор
|
|
Регистрация: 19.01.2012
Сообщений: 505
|
|
Если я правильно понял ваш код, то не хватает возврата результата 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/ чтобы там можно было сразу проверить.
Последний раз редактировалось Белый шум, 09.08.2017 в 23:54.
|
|
10.08.2017, 05:56
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Сообщение от Белый шум
|
Если я правильно понял ваш код, то не хватает возврата результата 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();
};
|
|
10.08.2017, 05:58
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Сообщение от Rise
|
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());
|
Интересное решение. Попробую реализовать при помощи данного подхода. Отпишусь, когда закончу.
|
|
10.08.2017, 08:22
|
|
Профессор
|
|
Регистрация: 19.01.2012
Сообщений: 505
|
|
Сообщение от koha345
|
Мне кажется, в ходе рекурсии первый вызов не вызывает resolve. Т.е. deffered теряется и никогда не вызывается, а на последнем шаге он вызывается, но возвращается в предыдущий вызов, но там никакого обработчика нет.
|
Да, что-то я не то предложил. Попробуйте передавать в рекурсивную ф-ю текущий dfd параметром, как-то так:
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();
Последний раз редактировалось Белый шум, 10.08.2017 в 08:30.
|
|
12.08.2017, 09:27
|
Интересующийся
|
|
Регистрация: 16.04.2016
Сообщений: 28
|
|
Сообщение от Rise
|
koha345,
Обновил пост.
|
Посмотрел. Не то, что я хотел, но это подкинуло мне мысль, которую я довел до конца.
К сожалению, уже сил и желания нет сидеть с этим Deffered. Нашкодил массив из вызываемых функций и пихаю в функцию, которая управляет очередью. В вызываемых функциях после ajax-запроса устанавливаются управляющие флаги и вызывается функция управления очередью, которая по полученным флагам принимает решение: запустить очередную итерацию или переходить к следующей функции.
В конечном счете я добился своего: создается иллюзия, будто запустил скрипт последовательно.
Нашкодил много, что выкладывать подобное даже не хочется.
За трату своего времени всем спасибо. В репутации отмечу.
|
|
|
|