简体   繁体   English

异步递归函数结束后的回调

[英]Callback after end of asynchronous recursive function

The function below prints Chrome bookmarks in a folder recursively. 下面的功能以递归方式打印文件夹中的Chrome书签。 How could I alter the below function to call another function after the final recursive loop is processed? 在处理完最后的递归循环后,如何更改下面的函数以调用另一个函数? chrome.bookmarks.getChildren() is asynchronous which makes it difficult to know when the function is done processing everything. chrome.bookmarks.getChildren()是异步的,这使得很难知道函数何时完成了对所有内容的处理。

Thanks. 谢谢。

    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: Sorry, I don't think I was clear in the initial code example. 编辑:对不起,我不认为我在初始代码示例中很清楚。 I've updated the code to show the problem I'm having with the asynchronous function by calling the function multiple times. 我已经更新了代码,通过多次调用该函数来显示异步函数存在的问题。 I'd like any code after the printBookmarks function calls to wait for all the printBookmarks functions to finish processing. 我想要在printBookmarks函数调用之后等待所有printBookmarks函数完成处理的任何代码。

Your asynchronous method instances may all be executing at once, and you don't know how many there will be beforehand. 您的异步方法实例可能全部一次执行,并且您不知道事先会有多少个实例。 So, you'll have to keep count and then use a callback when the last asynchronous method is done. 因此,您必须保留计数,然后在完成最后一个异步方法时使用回调。

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

I've recently had to solve this problem. 我最近不得不解决这个问题。 The solution was similar to Eric's, but I found that I needed the count variable to be local to the function. 该解决方案类似于Eric的解决方案,但是我发现我需要count变量在该函数中是局部的。 Here's how I would solve this: 这是我要解决的方法:

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

It's a bit ugly, but it should work. 这有点难看,但应该可以。

您可以执行类似JQFAQ.com的操作 。我正在为将来的使用进行更新。

You could save all your completed calls into a variable and test against the number of bookmarks you want to process. 您可以将所有已完成的调用保存到变量中,并根据要处理的书签数量进行测试。 When you reach the end (the count of completions equals the amount of bookmarks to process), then you execute your final function. 当到达末尾时(完成计数等于要处理的书签数量),然后执行最终功能。

An answer to a similar problem is here, with code that you can use as a guide: 这里有一个类似问题的答案,其中的代码可以用作指导:

How do I load a variable number of scripts with jQuery.getScript() before running javascript code? 在运行JavaScript代码之前,如何在jQuery.getScript()中加载可变数量的脚本?

Might be a better way to go about this, but you could add a depth parameter, something like 可能是解决此问题的更好方法,但是您可以添加depth参数,例如

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

EDIT in response to comment 编辑以回应评论

This is a variation on another answer for a slightly different approach. 这是另一个答案的变体,只是方法略有不同。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM