1

我目前正在开发一个基于 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);
    });
};

提前致谢。

4

2 回答 2

1

有四个问题:

  • 你的函数buildIndex没有return承诺,所以调用它时不能等待结果
  • 遇到目录时,您会buildIndex递归调用,但不要像promesse在 else 情况下那样尝试等待其结果。
  • 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(…);
}
于 2017-07-28T14:12:22.517 回答
0

使用 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 的回答和帮助的人。

于 2017-07-31T06:50:08.603 回答