【问题标题】:Wait till all items from mongoDB query are processed before continuing等到 mongoDB 查询中的所有项目都处理完毕后再继续
【发布时间】:2017-09-27 15:17:32
【问题描述】:

我正在处理一个非常复杂的项目,其中必须处理大量 mongoDB 查询才能显示数据。目前,在对大量数据执行查询时,并非所有数据都会在页面加载后立即显示。现在我通过设置超时函数来解决这个问题,然后再使用next() 函数。

所以这是调用其中一个函数的地方:

router.get('/playwall', account.checkSession, playwalls.get, function(req, res, next) {
  res.render('dashboard/playwalls/index');
});

检查用户是否登录后,playwalls.get 函数会触发。这就是该功能现在的工作方式:

const playwalls = {
  /* GET ALL PLAYWALLS FOR THAT USER, FOR ADMIN GET THEM ALL
  -------------------------------------------------------------- */
  get(req, res, next) {
    req.session.playwalls = [];
    const dataCollection = db.collection('data');
    const data = dataCollection.find({});
    console.log(typeof data)
    const today = new Date();
    data.forEach(function(d) {
      console.log(data.length)
      if(d.admin == req.session.userData.username || req.session.userData.role == 'admin') {
        const expireDate = new Date(d.date);
        if(expireDate < today && d.status == 'actief') {
          playwalls.editStatus(d, req, res, next);
        }
        req.session.playwalls.push(d);
      }
    })
    setTimeout(function() {
      next();
    }, 1000)
  },
  // Here the rest of the methods
}

我的问题是;我怎样才能确保next() 函数仅在data.forEach 循环已处理查询返回的所有文档时才被触发?这样我就可以摆脱setTimeout() 函数了。

希望我的问题很清楚,有人可以帮助我。我在互联网上四处寻找,但找不到正确的答案。

提前致谢!

【问题讨论】:

  • 你可以使用promises
  • 您可以将完成执行所需的代码包装在一个 Promise 中。 IE。将 forEach 放入一个单独的函数中,该函数返回一个 Promise,然后在它当前所在的位置解析它并调用 next
  • 你应该开始使用promises。但你也可以查看async 回调库
  • 感谢您的所有回答,这些对我来说都是新事物。但我会更多地了解他们!谢谢!
  • 是的,承诺。特别是,寻找“Promise.all()”......你的代码看起来有点像Promise.all(editResponses).then(next)

标签: javascript node.js mongodb loops settimeout


【解决方案1】:

你应该使用Cursor.toArray,这样你就可以以同步的方式迭代你的文档,然后如果你需要在forEach回调中做一些异步工作,你可以使用Promise's

const playwalls = {
    /* GET ALL PLAYWALLS FOR THAT USER, FOR ADMIN GET THEM ALL
    -------------------------------------------------------------- */
    get(req, res, next) {
        req.session.playwalls = [];
        const dataCollection = db.collection('data');
        const data = dataCollection.find({});
        console.log(typeof data)
        const today = new Date();
        data.toArray(function (err, documents) {
            if (err) {
                return next(err);
            }
            documents.forEach(function (d) {
                console.log(data.length)
                if (d.admin == req.session.userData.username || req.session.userData.role == 'admin') {
                    const expireDate = new Date(d.date);
                    if (expireDate < today && d.status == 'actief') {
                        playwalls.editStatus(d, req, res, next);
                    }
                    req.session.playwalls.push(d);
                }
            })
            next();
        })
    }, // Here the rest of the methods
}

【讨论】:

  • 调用 playwalls.editStatus 时这是否仍会导致计时问题?
  • 如果这是 expressjs 的下一个回调,它不应该在循环中传递
【解决方案2】:

如何定义一个返回promise 的函数。

所以,将forEach 拉出到一个单独的函数中:

function promisedForEach(data) {
    return new Promise(resolve => {
        // your code
        resolve('ready')
     }
 }

然后调用函数代替你的 forEach:

promisedForEach(data).then( /* carry on */ ) 

【讨论】:

  • 您在新的承诺@bazzells 处缺少右括号
【解决方案3】:

我不认为 setTimeout 会起作用,因为所有事情都必须在同一个线程中发生。所以 setTimeout 只会在轮到它执行时冻结。

另一种方法是使用 rxjs 观察者。 https://github.com/ReactiveX/RxJS 当您想在渲染页面之前等待应用程序的其他部分(例如中间件)中的内容时,这可能很有用。

您可以执行以下操作。我没有测试过这个。我只是给你一些想法;

global.Rx = require('rxjs/Rx');

router.get('/playwall', function(req, res) {
  const myProcesses = {
    ready:  new Rx.Subject(false),
    loading:  false,
    readiness: {
      process1: {
        ready: false
      },
      process2: {
        ready: false
      },
      process3: {
        ready: false
      }
    },
    checkReadiness: function (){
      if (
        this.readiness.process1==true
        && this.readiness.process2==true
        && this.readiness.process3==true
      ) {
        this.loading = false;
        this.ready.next(true);
      }
    },
  };
  //asynchronous process
  (function (){
    anObject.fetchAll().then(function (results){
      myProcesses.readiness.process1 = true;
      myProcesses.checkReadiness();
    })
  })();

  //another asynchronous process
  (function (){
    anObject2.fetchAll().then(function (results){
      myProcesses.readiness.process2 = true;
      myProcesses.checkReadiness();
    })
  })();

  //another asynchronous process
  (function (){
    anObject2.fetchAll().then(function (results){
      myProcesses.readiness.process3 = true;
      myProcesses.checkReadiness();
    })
  })();

  //When all asynchronous processes have been completed
  myProcesses.ready.subscribe({next: (v) => {
    if (v==true){
      res.render('ejs/products/checkout', {});
    }
  }});
});

【讨论】:

    猜你喜欢
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 2019-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多