Подтвердить что ты не робот

Обратный вызов после завершения асинхронной рекурсивной функции

Функция ниже печатает закладки 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);
           });
        });
    }

EDIT: Извините, я не думаю, что был ясен в первом примере кода. Я обновил код, чтобы показать проблему с асинхронной функцией, вызвав функцию несколько раз. Мне нужен любой код после вызова функции printBookmarks для ожидания завершения всех функций printBookmarks.

4b9b3361

Ответ 1

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

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

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

for(var i=0;i<foldersArray.length; i++){
  // The loop make several call 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();
    }
  });
}

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

Ответ 3

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

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--;
        });
    });
}

Ответ 4

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

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

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

Ответ 5

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