Node.js - 对象在函数后丢失值

时间:2018-01-21 04:40:09

标签: node.js

我使用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!');
});

3 个答案:

答案 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。