2017-07-27 134 views
0

我目前正在研究一个项目,在基于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); 
    }); 
}; 

在此先感谢。

+2

您不在等待递归调用的结果 - 它不返回承诺,也不会将其放入数组中。 – Bergi

+0

@DnzzL是'rawIndex.add'的异步调用? –

+0

@Bergi确实。我不知道如何正确实施它。 – DnzzL

回答

0

及如何使用foreach是不是让一心要返回无极正确的选择。 因此,使用.map,然后在if/else语句中返回Promises更为明智。 最后,我们必须调用Promises.all(promise),然后(...)按预期使用。

我的最终功能:

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的回答和那些谁帮助。

0

有四个方面的问题:

  • 你的功能buildIndexreturn的承诺,所以调用它时
  • 当遇到一个目录,你叫buildIndex递归但不要一个不能等待结果尝试等待其结果,就像您在其他情况下使用promesse所做的一样。
  • 在异步回调中有promesses.push(promesse);调用,只有在读入文件后才会执行该调用。将承诺放入数组中的想法是正确的,但必须立即执行,以便在调用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(…); 
} 
+0

非常感谢你从一个新的JS学习者那里获得的时间,它似乎工作得很好。 – DnzzL