【问题标题】:NodeJS running a promise-mysql query inside a foreach loop waiting for result each timeNodeJS 在 foreach 循环中运行 promise-mysql 查询,每次都等待结果
【发布时间】:2017-05-16 19:30:07
【问题描述】:

我正在尝试查询 mysql 数据库两次,第二次,对于第一次的每个结果多次,但我无法弄清楚如何在继续之前等待第二次查询的结果

 admin.get('/', function (req, res) {
        mysqlQ("SELECT I.ID as ID, C.ID AS CID, I.PD AS PostDate, C.Name AS CatName, U.UserName AS UserName, I.Title AS Title, I.Post AS PostData FROM categories AS C JOIN INAT AS I ON C.ID = I.Category JOIN Users AS U on U.ID = I.User").then(function (INAT) {
        INAT.forEach(function (team) {
            team.time = moment(team.PostDate).format("DD-MM-YYYY HH:mm:ss");
            team.TS = moment(team.time, "DD-MM-YYYY HH:mm:ss").fromNow();
            mysqlQ("SELECT I.ID AS InatID, J.Name AS JobTitle, C.Name AS Category FROM `Jobs` AS J JOIN Jobs2INAT AS J2I ON J.ID = J2I.JobsID JOIN INAT AS I ON I.ID = J2I.INATID JOIN categories AS C on C.ID = J.Categories WHERE I.ID = " + team.ID).then(function (jobs) {
                    team.jobs = jobs;
                });
        });
        var context = {
            INAT: INAT
        };
        var homeTemplate = pug.compileFile(__dirname + '/templates/home.pug');
        var html = homeTemplate(context);
        res.send(html);
    });
})

【问题讨论】:

标签: javascript mysql sql node.js express


【解决方案1】:

您实际上需要创建第二个承诺,该承诺将在 所有 您的辅助查询返回后解决,使用 when.all()bluebird.all(或它们等效的 *.map)构建第二个承诺

您还尝试修改 INAT 对象中的条目,但要这样做,您也需要等待辅助承诺解决,然后再更新 INAT 并发送最终结果。

有很多方法可以做到这一点,但这样的事情应该可以工作

var Promise = require('bluebird'); // or use any other Promise library

admin.get('/', function (req, res) {
    mysqlQ("SELECT I.ID as ID, C.ID AS CID, I.PD AS PostDate, C.Name AS CatName, U.UserName AS UserName, I.Title AS Title, I.Post AS PostData FROM categories AS C JOIN INAT AS I ON C.ID = I.Category JOIN Users AS U on U.ID = I.User")
        .then(function (INAT) {
            var promiseArray = [];
            promiseArray.push(Promise.resolve(INAT));
                // For each INAT entry create a new Promise that will resolve with your job
                INAT.forEach(function (team) {
                    team.time = moment(team.PostDate).format("DD-MM-YYYY HH:mm:ss");
                    team.TS = moment(team.time, "DD-MM-YYYY HH:mm:ss").fromNow();
                    promiseArray.push(
                        mysqlQ("SELECT I.ID AS InatID, J.Name AS JobTitle, C.Name AS Category FROM `Jobs` AS J JOIN Jobs2INAT AS J2I ON J.ID = J2I.JobsID JOIN INAT AS I ON I.ID = J2I.INATID JOIN categories AS C on C.ID = J.Categories WHERE I.ID = " + team.ID)
                    );
                });

            return Promise.all(promiseArray);
        }).then(function(results) {
            // Add the looked-up jobs to INAT
            var [INAT, ...jobs] = results;
            INAT.forEach(function(team, i) {
                team.jobs = jobs[i];
            })

            // Send your answer
            var context = {
                        INAT: INAT
            };
            var homeTemplate = pug.compileFile(__dirname + '/templates/home.pug');
            var html = homeTemplate(context);
            return res.send(html);
        }).catch(function(err) {
            // do some error handling
            return res.send("Unable to process / => err = "+err);
        })
    })

PS : 不要忘记以 return 声明结束所有 .then(function() {})

【讨论】:

  • 谢谢你,真的帮助我理解了承诺!
  • @bertie.io 我已经应用了你的编辑,据我说编辑审核队列错误地拒绝了,如果鲍里斯想回滚,他可以这样做。
【解决方案2】:

你的问题是这样的,你试图在第二个承诺解决之前分配你的变量。

如果你在等待2个promise返回,最后的动作需要在最后一个promise解决后执行

 admin.get('/', function (req, res) {
    mysqlQ("SELECT I.ID as ID, C.ID AS CID, I.PD AS PostDate, C.Name AS CatName, U.UserName AS UserName, I.Title AS Title, I.Post AS PostData FROM categories AS C JOIN INAT AS I ON C.ID = I.Category JOIN Users AS U on U.ID = I.User").then(function (INAT) {
    INAT.forEach(function (team) {
        team.time = moment(team.PostDate).format("DD-MM-YYYY HH:mm:ss");
        team.TS = moment(team.time, "DD-MM-YYYY HH:mm:ss").fromNow();
        mysqlQ("SELECT I.ID AS InatID, J.Name AS JobTitle, C.Name AS Category FROM `Jobs` AS J JOIN Jobs2INAT AS J2I ON J.ID = J2I.JobsID JOIN INAT AS I ON I.ID = J2I.INATID JOIN categories AS C on C.ID = J.Categories WHERE I.ID = " + team.ID).then(function (jobs) {
                team.jobs = jobs;

                //  *************<<<<<<<<<<<
                //  Any code that needs to wait for the second mysqlQ query needs to go here
                //  *************<<<<<<<<<<<
              var context = {
                  INAT: INAT
              };
              var homeTemplate = pug.compileFile(__dirname + '/templates/home.pug');
              var html = homeTemplate(context);


            });
    });
    res.send(html);
    // var context = {
    //     INAT: INAT
    // };
    // var homeTemplate = pug.compileFile(__dirname + '/templates/home.pug');
    // var html = homeTemplate(context);
    // res.send(html);
});

})

类似上面的方法可以工作,虽然仍然有点老套,并且可能由于 JS 开发人员喜欢的“回调/承诺地狱”而被不赞成。

【讨论】:

  • 这将导致每次foreach循环运行时都会发送Express请求,每次向浏览器发送请求
  • @bertie.io 你是对的!编辑我的帖子来解决这个问题。不能两次发送标头。
猜你喜欢
  • 2018-02-12
  • 2015-10-24
  • 2019-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
相关资源
最近更新 更多