Обратный вызов после завершения асинхронной рекурсивной функции - PullRequest
17 голосов
/ 19 февраля 2011

Приведенная ниже функция рекурсивно печатает закладки Chrome в папке.Как я могу изменить приведенную ниже функцию для вызова другой функции после обработки последнего рекурсивного цикла?chrome.bookmarks.getChildren() асинхронный, что затрудняет определение того, когда функция завершает обработку всего.

Спасибо.

    for (var i = 0; i < foldersArray.length; i++) {
        // The loop makes several calls with different folder IDs.
        printBookmarks(foldersArray[i]);  
    }

    // I'd like any code here to be run only after the above has 
    //finished processing    

    function printBookmarks(id) {
        chrome.bookmarks.getChildren(id, function(children) {
           children.forEach(function(bookmark) { 
               console.debug(bookmark.title);
               printBookmarks(bookmark.id);
           });
        });
    }

РЕДАКТИРОВАТЬ: Извините, я не думаю, что я был яснопример исходного кода.Я обновил код, чтобы показать проблему с асинхронной функцией, вызвав ее несколько раз.Я хотел бы, чтобы любой код после вызова функции printBookmarks ожидал завершения всех функций printBookmarks.

Ответы [ 5 ]

26 голосов
/ 19 февраля 2011

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

for (var i = 0; i < foldersArray.length; i++) {
    // The loop makes several calls with different folder IDs.
    printBookmarks(foldersArray[i], thingsToDoAfter);
}

function thingsToDoAfter() {
    // I'd like any code here to be run only after the above has 
    // finished processing.
}

var count = 0;

function printBookmarks(id, callback) {
    count++;
    chrome.bookmarks.getChildren(id, function(children) {
        children.forEach(function(bookmark) { 
            console.debug(bookmark.title);
            printBookmarks(bookmark.id, callback);
        });
        count--;
        if (count === 0 && callback)
            callback();
    });
}
2 голосов
/ 05 октября 2012

Мне недавно пришлось решить эту проблему. Решение было похоже на решение Эрика, но я обнаружил, что мне нужно, чтобы переменная count была локальной для функции. Вот как бы я решил это:

for(var i=0;i<foldersArray.length; i++){
  // The loop make's several call's with different folder ID's.
  var printed_children = 0;
  printBookmarks(foldersArray[i],function() {
    printed_children++;
    if(printed_children == foldersArray.length){
      // You know you are done!
    }
  });  
}
// I'd like any code here to be run only after the above has 
//finished processing.


function printBookmarks(id,finished_callback) {
  // the printed_children count is local so that it can keep track of 
  // whether or not this level of recursion is complete and should call 
  // back to the previous level
  var printed_children = 0;
  chrome.bookmarks.getChildren(id, function(children) {
    children.forEach(function(bookmark) { 
      console.debug(bookmark.title);
      // added a callback function to the printBookmarks so that it can
      // check to see if all upstream recursions have completed.
      printBookmarks(bookmark.id,function() {
        printed_children++;
        if(printed_children == children.length){
          finished_callback();
        }
      });
    });
    if(children.length == 0){
      finished_callback();
    }
  });
}

Это немного некрасиво, но должно работать.

0 голосов
/ 07 января 2013

вы можете сделать что-то вроде этого JQFAQ.com . Я обновляюсь для будущего использования.

0 голосов
/ 19 февраля 2011

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

Здесь вы найдете ответ на аналогичную проблему с кодом, который вы можете использовать в качестве руководства:

Как загрузить переменное число сценариев с помощью jQuery.getScript () перед запуском кода JavaScript?

0 голосов
/ 19 февраля 2011

Возможно, это лучший способ, но вы можете добавить параметр глубины, например,

printBookmarks('0', 0);

function printBookmarks(id, depth) {
    chrome.bookmarks.getChildren(id, function(children) {
        children.forEach(function(bookmark) { 
            console.debug(bookmark.title);
            printBookmarks(bookmark.id, depth + 1);
        });
        if(depth == 0) yourFunction();
    });     
}

РЕДАКТИРОВАТЬ в ответ на комментарий

Это вариант другого ответа для немного другого подхода.

runCount = 0;
for (var i = 0; i < foldersArray.length; i++) {
    // The loop makes several calls with different folder IDs.
    printBookmarks(foldersArray[i]);  
    runCount++;
}

while(runCount > 0) { // sleep for 10ms or whatnot}
// I'd like any code here to be run only after the above has 
// finished processing.    

function printBookmarks(id) {
    chrome.bookmarks.getChildren(id, function(children) {
        children.forEach(function(bookmark) { 
            console.debug(bookmark.title);
            printBookmarks(bookmark.id);
            runCount--;
        });
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...