Javascript - 如何确保(递归)函数调用的控制流

时间:2018-03-29 15:54:58

标签: javascript

我已经编写了这个递归函数,它根本没有表现得像预期的那样。所以在调试中我发现JS不仅跳过递归调用而且还跳过函数并继续执行,然后在看到合适的时候运行函数调用,从而弄乱了列表的整个顺序。
我可以以某种方式让它不那样做吗?我已对代码进行了评论,以便进一步解释。

private String getLabel(List<SelectItem> list, String selection) {
    String label = "";
    for (int i = 0; i < list.size(); i++) {
        if(selection.equals((String)list.get(i).getValue())) {
            label = (String)list.get(i).getLabel();
            break;
        }
    }

    return label;
}

1 个答案:

答案 0 :(得分:0)

递归和异步是开发人员的两个很好的工具,不幸的是他们彼此不喜欢的一个根本原因:递归使用执行堆栈来创建返回对象的结构,而javascript的异步机制有目的地让执行堆栈的当前迭代在执行异步操作之前运行。实质上,回调是执行堆栈帧的当前函数的返回地址的异步版本。你明白我的意思了吗?

所以我们喜欢递归,因为执行引擎会为我们处理响应的结构,但我们喜欢异步,因为文件系统很慢,我们不想挂断执行。

那么我们如何将方形钉子压入圆孔?我们可以保持假装递归级别,它将作为计数器告诉我们何时递归完成。这是我对它的看法,但它适用于NodeJS:

const fs = require('fs');

//These keep track of the recursion.
var recurseLevel = 0;
var paths = [];

function AsyncRecurse(path) {
  recurseLevel += 1;
  fs.readdir(path, createReadDirCallback(path));
}

//Because the callback of fs.readdir doesn't include the state I need (the current path we're investigating) I have to create a callback and pass the path by closure.
function createReadDirCallback(path) {
  return function (err, files) {
    if (err) {
      throw 'RIP';
    }
    files.forEach(file => {
      const fullPath = path + '\\' + file;
      paths.push(fullPath);
      if (fs.statSync(fullPath).isDirectory()) {
        AsyncRecurse(fullPath);
      }
    });
    recurseLevel -= 1;
    if (recurseLevel == 0) {
      //Only when I know for a fact all the recursion is complete can I confidently work with the results. This is the root of your problem: you start working with the result of your recursion long before it is done.
      finalCallback(paths);
    }
  }
}

function finalCallback(paths) {
  var html = '<ul>';
  paths.sort();
  paths.forEach(path => {
    //Build your html here synchronously.
  });
  //Your html is ready!
  console.log(paths);
}

AsyncRecurse(somePath);

我们在此处看到,我会跟踪最终的回复地址&#39;的递归和当前的递归级别。基本上我手动执行递归位,而我让javascript一个接一个地运行每个异步调用。

不幸的是,如果我们希望文件系统尽可能快地运行,那么我们将不得不用请求轰炸它并以无组织的方式接收响应。这就是我必须在最后对所有回复进行排序的原因。

您可以使用promises和promisify大量简化此解决方案。虽然这很有趣,但实质上你所做的是map-reduce,所以我建议你阅读并实现它。