Ooof。曾经有过这样的日子,你知道自己已经关闭了,但是你却无法得到它吗?
我正在写一个刽子手拼图解算器。这是在使用mongo db进行了node / hapi编写的服务中运行的。
所以我有一个功能:
solvePuzzle(puzzle, alreadyCalled);
args是拼图本身,解码后的字母为文字,未解决为?s,如下:
?O?N? ?O ?H? ?TO??
and alreadyCalled只是一个被称为但不正确的字母列表。经过一些捣乱之后,会为每个单词创建一个RegEx,然后将其发送到一个函数,该函数查询存储在mongo中的单词列表以进行匹配。
一切都在运作,如果我创建一个虚拟的单词列表作为一个简单的数组,一切正常,我得到一个匹配列表。
返回格式是一个对象数组,如下所示:(我在显示可能的解决方案时使用数组索引来保留单词顺序)
matches[0][?O?N?] = ['GOING', 'DOING', 'BOING'];
所以问到实际的问题。我将整个拼图分成单词,并在它们上面运行for循环,调用为每个拼图执行mongo查询的函数。问题是,在查询实际运行之前,函数调用似乎正在返回。散布在各处的控制台日志似乎承认了这一理论。
我尝试让查询函数返回一个承诺,但这只会让水更加混乱。我觉得我关闭但是 - 我不知道。这是我最初的非承诺代码:
function solvePuzzle(puzzle, called) {
// first build the exclusion match pattern
//console.log('solvePuzzle: building match pattern');
var x = buildMatchPattern(puzzle, called);
// split the puzzle into words
//console.log('solvePuzzle: tokenizing puzzle');
var words = tokenize(puzzle.toUpperCase());
//console.log('solvePuzzle:', words);
var results = [];
for(var i = 0; i < words.length; i++) {
console.log('solvePuzzle: matching ' + words[i]);
results[i] = {};
results[i][words[i]] = matchWord(words[i], x);
}
console.log('solvePuzzle: matches: ', results);
return results;
}
function matchWord(word, exclude) {
var pattern = '^';
var letters = word.toUpperCase().split('');
var matches = new Array();
var query = {};
//console.log('matchWord:', letters);
for(var i = 0; i < letters.length; i++) {
if(letters[i] !== '?') {
pattern += letters[i];
}
else {
pattern += exclude;
}
}
pattern += '$';
var re = new RegExp(pattern);
//console.log('matchWord:', re);
query.word = {"$regex" : re, "$options": "i"};
//console.log("matchWord query:", JSON.stringify(query));
db.wordlist.find(query, function (err, words) {
if(err) {
console.error('error:', err);
}
for(let i = 0; i < words.length; i++) {
if(words[i] !== null) {
console.log('loop:', words[i].word);
matches.push(words[i].word);
}
}
console.log('matchWord:', matches.length);
if(matches.length < 1) {
console.log('matchWord: found no matches');
matches.push('No Matches Found');
}
return matches;
});
}
所以我的控制台输出基本上是:
solvePuzzle: matching ?O?N?
solvePuzzle: matches: [] <---- problem
loop: 'going'
loop: 'doing'
etc etc.
.
.
matchWord: 5 (number of matches found);
正如您所看到的,对matchWord的调用是在实际查询运行之前返回的。所以我从来没有做过mongo支持的hapi服务。我如何构造这个代码,使它循环遍历所有单词,为每个单词查询mongo,并返回单个数组作为结果?
TIA。
答案 0 :(得分:0)
在节点中,数据库调用是异步的,因此您不能像这样使用return
。
您需要使用Promise(node.js中的native)
此代码应该有效:
function solvePuzzle(puzzle, called) {
var results = [];
// first build the exclusion match pattern
var x = buildMatchPattern(puzzle, called);
// split the puzzle into words
var words = tokenize(puzzle.toUpperCase());
// an array to store the words index
var indexes = Array.apply(null, {
length: words.length
}).map(Number.call, Number); // looks like [1, 2, 3, 4, ...]
// create a Promise for each word in words
var promises = indexes.map(function(index) {
return new Promise(function(resolve, reject) {
console.log('solvePuzzle: matching ' + words[index]);
results[index] = {};
var pattern = '^';
var letters = words[index].toUpperCase().split('');
var matches = new Array();
var query = {};
for (var i = 0; i < letters.length; i++) {
if (letters[i] !== '?') {
pattern += letters[i];
} else {
pattern += exclude;
}
}
pattern += '$';
var re = new RegExp(pattern);
query.word = {
"$regex": re,
"$options": "i"
};
db.wordlist.find(query, function(err, wordsRes) {
if (err) {
console.error('error:', err);
reject(err); // if request failed, promise doesn't resolve
}
for (let i = 0; i < wordsRes.length; i++) {
if (wordsRes[i] !== null) {
console.log('loop:', wordsRes[i].word);
matches.push(wordsRes[i].word);
}
}
console.log('matchWord:', matches.length);
if (matches.length < 1) {
console.log('matchWord: found no matches');
matches.push('No Matches Found');
}
results[index][words[index]] = matches;
resolve(); // request successfull
});
});
});
// when all promise has resolved, then return the results
Promise.all(promises).then(function() {
console.log('solvePuzzle: matches: ', results);
return results;
});
}