我使用Mongoose在Node.js中有一个REST API。我有以下功能,可以为我的应用程序执行特定的操作。问题是我设置test.questions
值并且在特定循环之后,我发现它正在丢失这些变量的范围。这里有什么问题?这是我的代码:
randomizeTest = (req, res) => {
const test = new Test;
let questions: String[] = [];
let num = 5;
while (num >= 1) {
var self = this;
this.quesmodel.count().exec(function (err, count) {
var random = Math.floor(Math.random() * count)
self.quesmodel.findOne().skip(random).exec(
function (err, result) {
questions.push(result._id);
test.questions = questions;
console.log(test.questions); // prints data
});
});
num--;
}
console.log(test.questions); // prints nothing
test.save(function (err, test) {
if (err) {
res.sendStatus(400);
console.error(err);
} else {
res.status(200).json({ test });
}
});
}
在Navid的回答之后,我现在尝试了这个:
let questions: String[] = [];
let num = 5;
var self = this;
asyncLoop(questions, function (item, next) {
while (num >= 1) {
self.quesmodel.count().exec(function (err, count) {
var random = Math.floor(Math.random() * count)
self.quesmodel.findOne().skip(random).exec(
function (err, result) {
questions.push(result._id);
test.questions = questions;
next();
});
});
num--;
}
}, function () {
console.log(test.questions);
console.log('Finished!');
});
答案 0 :(得分:1)
在nodejs函数中,一些I / O作业异步运行,因此当一个线程在循环并执行数据库I / O作业时循环时,另一个正在运行其余代码并执行{ {1}}以前的值为空。
PS。处理这类问题的一个好方法是使用一些异步库来按顺序运行循环,如node-async-loop。
console.log(test.questions);
这可能会对您有所帮助,但这不是最好的方法:
var asyncLoop = require('node-async-loop');
var array = ['item0', 'item1', 'item2'];
asyncLoop(array, function (item, next)
{
do.some.action(item, function (err) //database operations come here
{
if (err)
{
next(err);
return;
}
next();
});
}, function (err)
{
if (err)
{
console.error('Error: ' + err.message);
return;
}
// the rest of your code like console.log(test.questions); goes here
console.log('Finished!');
});
答案 1 :(得分:0)
这里是使用mongodb内置的promises(这是一种管理多个异步操作的更好方法)的解决方案,然后使用async/await
简化一些事情,这样你的循环实际上是串行运行的:
randomizeTest = async (req, res) => {
const test = new Test();
let questions: String[] = [];
test.questions = questions;
try {
for (let num = 5; num >= 1; --num) {
let count = await this.quesmodel.count();
let random = Math.floor(Math.random() * count);
let result = await this.quesmodel.findOne().skip(random).exec();
questions.push(result._id);
}
console.log(test.questions); // prints final results
await test.save();
res.status(200).json({ test });
} catch(e) {
res.sendStatus(500);
console.error(e);
}
}
仅供参考,如果在您选择随机记录时有其他进程修改该集合,则从集合中选择随机记录的方案将受到竞争条件的影响。这是因为从.count()
到.skip(random)
之间的时间段可以在该时间窗口中更改集合。有多种其他技术可以选择一个随机项目,每个项目都有自己最适合的情况。
答案 2 :(得分:-1)
我肯定肯定这是你的循环问题。请使用async代替while。