我有一个 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相关问答推荐

Puppeteer 的 BrowserFetcher 发生了什么?

如何从 Mongo Atlas 触发器向 GCP PubSub 发出经过身份验证的请求

如果我在 tsx 文件中使用了use client,ssr 会如何发生?

当API返回400状态代码时,使用Reactjs fetch获取错误消息

Redis Typescript 删除方法类型转换

Promise 和 Azure 语音转文本

TypeScript Eslint警告了一个AWS客户端构造函数(dynamodb),但没有警告另一个(s3)

在生产环境中,Nest实例启动时抛出不完整的导入错误

在父模式中设置默认值.

如何在 node /快速服务器上配置 mongoDB

React Native:执行 com.android.build.gradle.internal.tasks.Workers$ActionFacade 时发生故障

仅显示用户在 Reactjs 中使用服务器端发布的帖子是 Node Js、Mongodb

node.js 中 pdfkit-tables 中的垂直线

如何在 Nest.js 中使用查询参数?

制作一个接受命令行参数的脚本

用于排除多个文件的 node.js glob 模式

在 Node.js 中的两个不同进程之间进行通信

使用 Webpack 和 font-face 加载字体

在 Node.js 中混合使用 JavaScript 和 TypeScript

expressjs app.VERB 调用中的 next() 和 next('route') 有什么区别?