2014-08-28 3 views
1

Мне нужно выполнить функцию после рекурсивных асинхронных вызовов ajax. у меня есть:Выполнить функцию после рекурсивных асинхронных вызовов ajax

var tree = [1, 2 ,3, 4]; 

recursion(0); 

function recursion(i) { 
    $.ajax('http://example.com/' + tree[i]) 
     .done(function (data) { 
     // data is array 
     ++i; 
     if (tree[i] !==undefined) { 
      $.each(data, function() { 
       recursion(i); 
      }); 
     } 
    }); 
} 

И я хочу после всех звонков, когда они сделаны сделать:

recursion(0).done(function() {alert('All calls are done!')}); 

Я знаю, я должен использовать $ .Deferred из JQuery, но Аякс вызова возвращения обещания слишком. Я пытаюсь использовать $ .Deferred, но я столкнулся с проблемой, с петлей в этом месте:

 $.each(data, function() { 
     recursion(i); 
    }); 

Пожалуйста, помогите мне.

+0

Ваш 'recursion()' даже не возвращает обещание. – Bergi

+0

Посмотрите на [этот вопрос] (http://stackoverflow.com/q/21762982/1048572), хотя и [здесь] (http: // stackoverflow.com/q/5627284/1048572) о том, как ждать нескольких 'recurse()' promises – Bergi

+2

Почему ваш рекурсивный вызов в цикле над 'data', когда он фактически не использует' data' для рекурсивного вызова? ? Нужно ли вообще быть рекурсивным? Возможно, вы захотите опубликовать свой фактический код. – Bergi

ответ

1

Я пытаюсь использовать $ .Deferred

Хорошо!

, но я столкнулся с проблемой, с петлей в этом месте: $.each(data, recursion)

Каждый из recursion(i) вызовов возвращает обещание, поэтому, когда мы выгнали их мы остались с коллекцией обещаний. Теперь мы можем использовать $.when до wait for all of them и получить обещание по всем их результатам.

Теперь мы используем then, чтобы связать это циклическое выполнение после вызова ajax, чтобы мы могли вернуть обещание для конечного результата этого этапа рекурсии.

function recursion(i, x) { 
    return $.ajax('http://example.com/' + tree[i] + x).then(function (data) { 
     if (++i < tree.length) 
      // get an array of promises and compose all of them 
      return $.when.apply($, $.map(data, function(d) { 
       return recursion(i, d); 
      })); 
     else // at the innermost level 
      return data; // get the actual results 
    }); // and return a promise for that 
} 
+0

Ваш ответ застревает в цикле :(, замораживая браузер, когда его пытают на 'console', на этой странице нет результатов возврата в jsfiddle http://jsfiddle.net/guest271314/x8a8brak /? Если возможно, можно создать jsfiddle, fork above, чтобы продемонстрировать ожидаемые результаты? fwiw, почему бы просто не составить и не отправить _own_ Ответ вместо того, чтобы анализировать усилия других пользователей _before_ публиковать собственный ответ? Или оба? Если ваши методы/Ответ действительно самый эффективный, ответ будет говорить сам за себя, нет? Возможно, может быть больше одного способа или «шаблона» для достижения тех же результатов? – guest271314

+2

Я думаю, что у вас есть ошибка 1 на ваш 'if (++ i ...' Когда '++ i' равно' tree.length', тогда 'tree [i]' будет не определено в вызовах 'recursion'. Вы также определяете параметр 'x', но никогда не передаете его. Это значит, что любой бит информации вытаскивается из «данных» в цикле? –

+0

@ guest271314 Для чего это стоит, я очень оценил замечания Берги по моему ответу и, как результат, улучшил мое использование обещаний на будущее. Я предполагаю, что моя медлительность в рассмотрении его комментариев привела к тому, что он опубликовал свой собственный ответ. Я часто делаю то же самое. Если ответ подобен тому, на что я бы ответил, но пропустил несколько ключевых моментов, я укажу их и позволю ответчику обновить свой ответ, а не опубликовать очень похожий ответ. Если ответчик не будет (или не хочет) обновляться, я опубликую свое собственное. –

0

Чтобы сделать его простым, вы можете просто запустить функцию в своем .done, которая проверяет значение i и если она равна длине дерева (минус 1), а затем запустите свою функцию.

Извините, что не охватывает асинхронный характер ... вместо этого ... создайте переменную, которая отслеживает количество завершенных и сравнивается с числом в массиве. Когда вы равны, запустите свою функцию.

+0

Это не использует силу обещаний. – Bergi

+0

Просто простой способ получить работу. Простите, я еще не использовал обещания. –

+1

@ Шейн Стебнер, да, но проблема в цикле, в дереве последнего шага [3], когда я проверю «i», это условие будет выполняться столько же, сколько элемент в массиве данных – BottieYOYO

1

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

function recursion(i) { 

    return $.ajax('http://example.com/' + tree[i]) 
     .then(function (data) { 
      // data is array 
      ++i; 
      if (tree[i] !==undefined) { 

       // get an array of promises 
       var promises = $.map(data, function() { 
        return recursion(i); 
       }); 

       // return the `when` promise from the `then` handler 
       // so the outer promise is resolved when the `when` promise is 
       return $.when.apply($, promises); 
      } else { 
       // no subsequent calls, resolve the deferred 
      } 
     }); 
} 

В настоящее время не проверялось, но по крайней мере дает вам идею. В основном вы разрешаете только отсрочку, как только все последующие вызовы будут разрешены.

+0

Не используйте [отложенный антипаттерн] (https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#wiki-the-deferred-anti-pattern)! Вы даже знаете о '' $ .when' (http://api.jquery.com/jQuery.when/)! – Bergi

+0

@ Bergi Я чувствую, что в этом случае я, вероятно, пропустил что-то глупое, но что вы называете 'when' on? Список отложенных событий не существует в момент возвращения функции, а разрешение вызова ajax недостаточно, так как это слишком рано. –

+0

Но обещание ajax существует, на котором вам просто нужно [цепочка] (http://api.jquery.com/deferred.then/) ваши рекурсивные вызовы, которые в комплекте с этим «$ .when». Вероятно, мой комментарий был введен в заблуждение, ваше использование '$ .when' верное, использование' def' и 'ajax(). Done (...)' is not. – Bergi

0

Редактировать, jQuery deferred, promise на самом деле не требуется для достижения требования. См. Комментарий и ссылку Bergi, ниже.

Try (этот шаблон, безjquery.deferred или promise «s)

(function recursion() { 
     var tree = [1, 2 ,3, 4] 
     , results = [] 
     , dfd = function(res) { 
      alert('All calls are done!'); 
      console.log(res) 
     }; 

    $.each(tree, function(k, v) { 
     $.ajax("http://example.com/" + v) 
     .done(function (data, status, jqxhr) { 
     // data is array 
      results.push([data, status, jqxhr.state()]); 
      if (results.length === tree.length) { 
       dfd(results);   
      } 
     }); 

    }); 

    }()); 

jsfiddle http://jsfiddle.net/guest271314/nvs0jb6m/

+0

Почему вы возвращаете строку '' pending '' из IIFE? – Bergi

+0

Не используйте [отложенный антипаттерн] (https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns#wiki-the-deferred-anti-pattern)! Там уже есть [функция для этого] (http://api.jquery.com/jQuery.when/). – Bergi

+0

'pending' является' deferred.state() 'перед выполнением всех задач. Было бы лучше оставить полностью отложенное от этого? Будет повторно составлен и опубликован _without_ отложен. Спасибо – guest271314

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