Обратный вызов после завершения асинхронной рекурсивной функции
Функция ниже печатает закладки 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
.
Ответы
Ответ 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. Я обновляюсь для использования в будущем.