I'm currently working on a project to implement a full-text search client-side in JavaScript based on lunr.js.
The thing is, I'm struggling in building then saving the index because I have several asynchronous calls.
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);
});
};
Thanks in advance.
Using forEach wasn't the right choice to make as one wants to return a Promise. Thus it is wiser to make use of .map and then return Promises in the if/else statement. Finally, one has to call Promises.all(promises) making .then(...) usable as expected.
My final function:
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');
});
};
Thanks @Bergi for the answer and those who helped.