我有一个 node .js/Express应用程序,查询路由中的MySQL数据库,并向用户显示结果.我的问题是,在将用户重定向到他们请求的页面之前,如何运行查询并阻止,直到两个查询都完成?

在我的示例中,我有两个查询需要在呈现页面之前完成.如果我将查询2嵌套在查询1的"result"回调中,我可以让查询同步运行.然而,当查询数量增加时,这将变得非常复杂.

如何同步运行多个(在本例中为2)数据库查询,而不将后续查询嵌套在前一个查询的"result"回调中?

我已经研究了 node 模块中的"流控制/异步功能",并try 了Flow js,但我无法让它用于异步查询.

下面列出了我试图从"/home"路径执行的两个查询. node 专家能否解释一下这样做的"正确"方法.

app.get('/home', function (req,res) {
    var user_array = [];
    var title_array = [];

    // first query
    var sql = 'select user_name from users';
    db.execute(sql)
        .addListener('row', function(r) {
            user_array.push( { user_name: r.user_name } );
        })
        .addListener('result', function(r) {
            req.session.user_array = user_array;
        });

    // second query
    var sql = 'select title from code_samples';
    db.execute(sql)
        .addListener('row', function(r) {
            title_array.push( { title: r.title } );
        })
        .addListener('result', function(r) {
            req.session.title_array = title_array;
        });

        // because the queries are async no data is returned to the user
        res.render('home.ejs', {layout: false, locals: { user_name: user_array, title: title_array }});
});

推荐答案

node的目标不是关心事情发生的顺序.这可能会使某些情况复杂化.嵌套回调并不丢脸.一旦你习惯了它的外观,你可能会发现你实际上更喜欢这种风格.我愿意;很明显,将发起什么样的订单回调.如果必须的话,你可以放弃匿名函数来减少它的冗长.

如果您愿意稍微重新构造代码,可以使用"典型"嵌套回调方法.如果你想避免回调,有很多异步框架可以帮助你做到这一点.您可能想签出的是async.js(https://github.com/fjakobs/async.js). 每个示例:

app.get('/home', function (req,res) {
    var lock = 2;
    var result = {};
    result.user_array = [];
    result.title_array = [];

    var finishRequest = function(result) {
        req.session.title_array = result.title_array;
        req.session.user_array = result.user_array;
        res.render('home.ejs', {layout: false, locals: { user_name: result.user_array, title: result.title_array }});
    };

    // first query
    var q1 = function(fn) {
      var sql = 'select user_name from users';
      db.execute(sql)
          .addListener('row', function(r) {
              result.user_array.push( { user_name: r.user_name } );
          })
          .addListener('result', function(r) {
              return fn && fn(null, result);
        });
    };

    // second query
    var q2 = function(fn) {
      var sql = 'select title from code_samples';
      db.execute(sql)
          .addListener('row', function(r) {
              result.title_array.push( { title: r.title } );
          })
          .addListener('result', function(r) {
              return fn && fn(null, result);
          });
    }

    //Standard nested callbacks
    q1(function (err, result) {
      if (err) { return; //do something}

      q2(function (err, result) {
        if (err) { return; //do something}

        finishRequest(result);
      });
    });

    //Using async.js
    async.list([
        q1,
        q2,
    ]).call().end(function(err, result) {
      finishRequest(result);
    });

});

对于一次性,我可能只会使用引用计数类型的方法.只需跟踪要执行的查询数量,并在所有查询完成后呈现响应.

app.get('/home', function (req,res) {
    var lock = 2;
    var user_array = [];
    var title_array = [];

    var finishRequest = function() {
        res.render('home.ejs', {layout: false, locals: { user_name: user_array, title: title_array }});
    }

    // first query
    var sql = 'select user_name from users';
    db.execute(sql)
        .addListener('row', function(r) {
            user_array.push( { user_name: r.user_name } );
        })
        .addListener('result', function(r) {
            req.session.user_array = user_array;
            lock -= 1;

            if (lock === 0) {
              finishRequest();
            }
        });

    // second query
    var sql = 'select title from code_samples';
    db.execute(sql)
        .addListener('row', function(r) {
            title_array.push( { title: r.title } );
        })
        .addListener('result', function(r) {
            req.session.title_array = title_array;
            lock -= 1;

            if (lock === 0) {
              finishRequest();
            }
        });
});

一种更好的方法是,在呈现响应之前,只需在每个"result"回调中调用finishRequest()判断非空array.这是否适用于您的情况取决于您的要求.

Node.js相关问答推荐

express返回意外的URL

在Node.js下使用PostgreSQL客户端聚合PostgreSQL中的用户定义类型

如何使用聚合管道交换键值对

JEST模拟由http服务器控制器导入的ES模块

Socket.io 未将用户加入给定房间

为什么我的过滤器无法在我在下面编写的 Google Analytics 4 应用程序脚本代码中工作?我该如何修复它?

GitLab 依赖扫描需要源代码中的 package-lock.json 才能执行

Google App Engine 突然不允许我部署我的 node.js 应用程序

如何获取文件的中间值?

处理 UTC 日期和future

aws cdk 2.0 init 应用程序无法构建更漂亮的问题,这来自 jest-snapshot

如何在 TypeScript 中输出 Hackerrank 二叉树问题?

如何使用 superagent/supertest 链接 http 调用?

使用 nvm-windows 时更新 npm

使用 Node.JS,如何按时间顺序获取文件列表?

Node.js 应用程序有周期性的缓慢和/或超时(不接受传入的请求)

用一级 try ... catch 捕获 JavaScript Promise 中的错误

安装Node.js 安装n 安装Node.js?

要求('babel/register')不起作用

如何断言不为空?