如何在循环中承诺?

时间:2017-09-17 08:24:16

标签: node.js loops express promise

我正在尝试在nodejs中编写一个cron函数,它从db中获取所有用户的user_id,然后我想解析每个user_id。

这是我的代码:

cron.schedule('43 11 * * *', function(){
  var now = moment()
  var formatted = now.format('YYYY-MM-DD HH:mm:ss')
  console.log('Starting the cron boss!');
  var dbSelectPromise = function(db, sql1) {
      return new Promise(function(resolve, reject) {
          db.select(sql1, function(err, data) {
              if (err) {
                  reject(err)
              } else {
                  resolve(data)
              }
          })
      })
    }
    var users =[]
    var sql = "select distinct(user_id) from user_level_task"
    dbSelectPromise(db,sql).then(function(secondResult){
      for(i=0;i<secondResult.length;i++){
      var sql1 = "select max(level_id) as level from user_level_task where user_id ="+secondResult[i].user_id
      dbSelectPromise(db,sql1).then(function(thirdResult){
        console.log(thirdResult)
        console.log(current)
        var sql2 = "select task_id form user_level_task where user_id = '"+secondResult[i].user_id+"' and level_id = '"+thirdResult[0].level+"' "
        dbSelectPromise(db,sql2).then(function(fourthResult){
          var leng = fourthResult.length
          for(i=0;i<leng;i++){
            console.log(fourthResult[i])
          }
        })
      })
     }
    })
});

我面临的问题是我无法在第三和第四次承诺中获得i的价值。请帮忙!

2 个答案:

答案 0 :(得分:0)

我认为发生的事情是i在创建新的承诺时不再相同,因为for循环仍然在运行。看来您真正需要的是user_idlevel_id。我建议你稍微重构你的代码以减少嵌套并传递你未来承诺所需的值。

也许类似于此:

dbSelectPromise(db, sql)
.then(secondResult => {
  const levelPromises = [];
  secondResult.forEach(res => {
    levelPromises.push(getLevelByUserId(res.user_id, db));
  });      
  return Promise.all(levelPromises); // Promise.all only if you want to handle all success cases
})
.then(result => {
  result.forEach( level => {
    { userId, queryResult } = level;
    // ...
  })
  //...
})
.catch(err => {
  console.log(err);
});

function getLevelByUserId(userId, db) {
  const query = `select max(level_id) as level from user_level_task where user_id = ${userId}`;
  return dbselectPromise(db, query).then(result => { userId, result });
}

它创建一个包含所有获取级别查询的数组作为promises,然后使用Promise.all()将其传递到下一步,只有在所有查询都成功时才会解析。此时,您将再次访问每个结果的userId,因为我们在新函数中将其返回给您的下一组查询。

我认为你应该进一步抽象你的查询而不是使用通用dbSelectPromise而不要忘记catch(),否则你不会知道&#39发生了。

注意:它假定您的db变量已正确实例化,并且您的原始db.select不需要根​​据您正在使用的库返回。那里还有一些新的语法。

答案 1 :(得分:0)

  

我面临的问题是我无法在第三和第四次承诺中获得i的价值。请帮忙!

这是因为您在不使用i的情况下使用let重新初始化。当循环进行时,该值将与您期望的值不同。

  

每个承诺都依赖于另一个并且需要同步运行

为了实现这一点,你需要链接承诺。此外,您可以使用Promise.all()一次执行一连串的承诺。请记住,Promise.all()是全有或全无。

对代码进行这些更改后,我得到以下结构。

'use strict';

let _ = require('lodash');

function dbSelectPromise(db, sql1) {
  return new Promise((resolve, reject) => {
    return db.select(sql1, (err, data) => {
      if (err) {
        return reject(err);
      }
      return resolve(data);
    });
  });
}

function process(secondResult) {
  let sql1 = "select max(level_id) as level from user_level_task where user_id =" + secondResult[i].user_id;
  return dbSelectPromise(db, sql1).then(function (thirdResult) {
    console.log(thirdResult);
    let sql2 = "select task_id form user_level_task where user_id = '" + secondResult[i].user_id + "' and level_id = '" + thirdResult[0].level + "' ";
    return dbSelectPromise(db, sql2);
  });
}

function getUsers() {
  let sql = "select distinct(user_id) from user_level_task";
  return dbSelectPromise(db, sql).then((users) => {
    return users;
  }).catch(() => {
    return [];
  });
}

cron.schedule('43 11 * * *', function () {

  var now = moment();
  var formatted = now.format('YYYY-MM-DD HH:mm:ss');

  getUsers().then((users) => {
    let batches = _.map(users, function (user) {
      return process(user);
    });
    return Promise.all(batches);
  }).then((fourthResult) => {
    console.log('Your fourthResult [[],..]', fourthResult);
  }).catch(() => {
    console.log('err while processing', err);
  });
});