【问题标题】:How to handle async loop?如何处理异步循环?
【发布时间】:2017-07-31 14:50:08
【问题描述】:

我目前正在做一个项目,以基于 lunr.js 在 JavaScript 中实现全文搜索客户端。

问题是,我正在努力构建然后保存索引,因为我有几个异步调用。

    function buildIndex(rawIndex, root, indexPath = root + 'js/app/index.json') {
  var path = path || require('path');
  var fs = fs || require('fs'),
    promesses = [],
    ignore = ['node_modules'],
    files = fs.readdirSync(root);
  files.forEach(function (file) {

    if (fs.statSync(path.join(root, file)).isDirectory() && ignore.indexOf(file) == -1) {
      buildIndex(rawIndex, path.join(root, file), indexPath);
    }
    else if (file.substr(-5) === '.html' && file != 'example.html') {
      var promesse = JSDOM.fromFile(path.join(root, file)).then(dom => {

        var $ = require('../lib/_jquery')(dom.window);
        populate();
        console.log(file + " indexé");
        function populate() {
          $('h1, h2, h3, h4, h5, h6').each(function () {
            var title = $(this);
            var link = path.join(root, file).replace('..\\', '') + "#" + title.prop('id');
            var body = title.nextUntil('h1, h2, h3, h4, h5, h6');
            rawIndex.add({
              id: link,
              title: title.text().latinise(),
              body: body.text().latinise()
            });
          });
        };
      });
      promesses.push(promesse);
    }
  });
  Promise.all(promesses)
    .then(function () {
      fs.writeFileSync(indexPath, "var data = " + JSON.stringify(rawIndex), 'utf8');
    })
    .catch(function (err) {
      console.log("Failed:", err);
    });
};

提前致谢。

【问题讨论】:

  • 你不是在等待递归调用的结果——它没有返回一个承诺,你也没有把它放在你的数组中。
  • @DnzzL 是 rawIndex.add 异步调用吗?
  • @Bergi 确实如此。我不知道如何正确实现它。
  • @JamshidAsadzadeh 好吧,我不这么认为,至少文档中没有提到:lunrjs.com/docs/lunr.Builder.html。我宁愿说问题与 $('h1, h2, h3, h4, h5, h6').each() 和循环内循环有关。
  • @DnzzL 您对revision 3 的编辑使代码明显变差。如果你把它回滚,我不介意。

标签: javascript node.js asynchronous lunrjs


【解决方案1】:

有四个问题:

  • 你的函数buildIndex 没有return 承诺,所以调用它时不能等待结果
  • 遇到目录时,您会递归调用 buildIndex,但不要像在 else 情况下使用 promesse 那样尝试等待其结果。
  • 您在异步回调中调用了promesses.push(promesse);,该回调仅在读入文件后才执行。将promise 放入数组的想法是正确的,但您必须立即执行,以便它在Promise.all 之前发生在数组上调用。
  • 您出于某种原因从代码中删除了Promise.all

基本上这个函数应该有这个通用架构:

function buildIndex(…) {
  …
  var promises = paths.map(function(path) {
    if (isDir(path)) {
      return buildIndex(…);
    } else {
      return JSDOM.fromFile(…).then(…);
    }
  });
  return Promise.all(promises).then(…);
}

【讨论】:

  • 非常感谢一个新的 JS 学习者的宝贵时间,它似乎工作得很好。
【解决方案2】:

使用 forEach 不是正确的选择,因为人们想要返回一个 Promise。 因此,使用 .map 然后在 if/else 语句中返回 Promises 会更明智。 最后,必须调用 Promises.all(promises) 使 .then(...) 可以按预期使用。

我的最终功能:

function buildIndex(rawIndex, root, indexPath = root + 'js/app/index.json') {
  var path = path || require('path');
  var fs = fs || require('fs'),
    promises = [],
    ignore = ['node_modules'],
    files = fs.readdirSync(root);

  var promises = files.map(function (file) {
    if (fs.statSync(path.join(root, file)).isDirectory() && ignore.indexOf(file) == -1) {
      return buildIndex(rawIndex, path.join(root, file), indexPath);
    }
    else if (file.substr(-5) === '.html' && file != 'example.html') {
      return JSDOM.fromFile(path.join(root, file)).then(dom => {

        var $ = require('jquery')(dom.window);
        populate();
        console.log(file + " indexé");

        function populate() {
          $('h1, h2, h3, h4, h5, h6').each(function () {
            var title = $(this);
            var link = path.join(root, file).replace('..\\', '') + "#" + title.prop('id');
            var body = title.nextUntil('h1, h2, h3, h4, h5, h6');
            rawIndex.add({
              id: link,
              title: title.text().latinise(),
              body: body.text().latinise()
            });
          });
        };
      })
    }
  })
  return Promise.all(promises).then(function () {
    fs.writeFileSync(indexPath, "var data = " + JSON.stringify(rawIndex), 'utf8');
  });
};

感谢@Bergi 的回答和帮助的人。

【讨论】:

    猜你喜欢
    • 2012-04-04
    • 2016-10-25
    • 1970-01-01
    • 2019-03-12
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 1970-01-01
    相关资源
    最近更新 更多