NodeJS 6.9.3
假设我们使用的是PHP或Ruby等同步语言。我们经常会看到这种模式:
$all_results = [];
$array_of_words = get_relevant_words();
for ($i=0; $i < count($array_of_words); $i++) {
$word = $array_of_words[$i];
if (len($word) < 3) {
continue;
}
$results = database_call($word);
$all_results = array_merge($all_results, $results);
}
循环数组,进行数据库调用,并且有一些保护子句偶尔会强制代码跳过某些调用 - 这是一种标准模式,你几乎可以在所有代码库中找到它。
由于NodeJS是异步的,我们放弃了某些类型的控制流,我们必须努力让它们恢复。
上周我一直在研究这个问题,我大多数都想知道如何做到这一点,但是我的代码非常难看,我确信必须有一个更惯用的方法来做到这一点。的NodeJS。我很好奇惯用法是什么?
现在,我没有循环,而是递归回调:
return database_queries.profiles(word, array_of_words_from_string_from_api_call, index_to_read, map_of_profiles)
.then(function(results_from_database) {
map_of_profiles = Object.assign( map_of_profiles, results_from_database );
if (index_to_read < array_of_words_from_string_from_api_call.length - 1) {
return database_queries.profiles(word, array_of_words_from_string_from_api_call, index_to_read + 1, map_of_profiles);
} else {
return map_of_profiles;
}
该函数一直调用自己,直到索引到达数组中的最后一项。
在数据库查询功能中,我有我的保护条款:
if (!search_term || search_term == "") {
var thenable = { then: function(resolve) {
return new Error ({
"message" : "The search term was empty so we did not run the database query.",
"array_of_words_from_string_from_api_call" : array_of_words_from_string_from_api_call,
"index_to_read" : index_to_read,
"map_of_profiles" : map_of_profiles
});
}};
return thenable;
}
这是我的代码开始变得非常难看的地方:我正在传递array_of_words_from_string_from_api_call
之类的变量,以便我可以在错误中返回它们,这样它们就可以在catch()块中使用它捕获了这个错误。
最糟糕的是,我没有使用我的catch()块来处理真正的错误,而是复制了上面的所有递归代码,这些代码一直在调用database_queries.profiles()
。
返回错误是我能找到模仿传统护卫条款的唯一方法。我唯一可以处理此错误的地方是catch块。
在NodeJS中必须有一种不那么难看的方法。谁能告诉我惯用法是什么?
答案 0 :(得分:2)
一种可能性是使用异步库。它允许您并行或按定义的顺序运行异步代码(当调用相互依赖时)。 看看async documentation
在你的情况下,你可以使用async.each each,它将并行地对数组中的每个元素执行你的函数,最终将调用最终的回调。
在您的情况下,您可以考虑使用eachLimit来限制并行请求的数量,以免数据库因大量请求而崩溃。
const processWords = (words, done, limit = 5) => {
const results = [];
async.eachLimit(
words, // iteratable variable
limit, // concurrency limit
(word, next) => { // item processor
if (word.length < 3) {
return next();
}
database_call(word, (error, result) => {
if(error) return next(error);
if(result) results.push(result);
next();
});
},
error => done(error, results) // at the end of iteration
);
};
const words = ['hello', 'world'];
processWords(words, (error, result) => {
console.log(error, result);
});