取消嵌套节点数据库调用 [英] Unnesting Node database calls

查看:55
本文介绍了取消嵌套节点数据库调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个普通的

var express = require('express')

节点可以像往常一样使用会话,pug等来表示www页面.我的数据库调用

Node express www page, using session, pug, etc as usual. My db calls

var db = require('./scripts/myHappyMysqlScript')

我自然使用 mysql ,因此在db脚本中

I'm naturally using mysql, so in the db script

var mysql = require('mysql')

例如

app.get('/catPhotos', (req, response) => {
    response.render('catPhotos.pug');
})

说一个页面有一个表,该表显示了petNames数据库中的内容,

Say a page has a table showing something from the petNames database,

app.get('/pets', function(req, res, next) {
    db.allPetNames(function(err, petsList) {
        res.render('pets.pug',
            {
                'petsList': petsList,
                'pretty' : true
            })
    })

到目前为止一切都很好.

all good so far.

但是在这种情况下,pug页上有三个表,并且有三个不同的数据库调用:

But here's a case with three tables on the pug page, and three different database calls:

db.cats(function(err, c) {
    db.dogs(function(err, d) {
        db.budgies(function(err, b) {
            res.render('bigScreen.pug',
                {
                    'cats' : c,
                    'k9s': d,
                    'budgies': b,
                    'pretty' : true
                })
        })
    })
})

我就是这样嵌套它们的.

I just nest them like that.

这看起来确实不错.

它正确地顺序等待.错误会消失并得到正确处理,依此类推.

It correctly waits sequentially. Errors fall through and are handled properly, and so on.

但是还有更好的语法,更好的方法吗?真正的Node而不是Swift程序员的Node Way是什么?!

But is there a better syntax, better way? What's the Node Way for real™ Node, not-Swift, programmers?!

如果相关的话,也许我正在使用 mysql 库.

Perhaps given that I'm using the mysql library, if that's relevant.

请注意,总体上更好的方法是使用Ajax之类的内容仅流式传输每个部分"中的内容.网页的确实,我一直都这样做.我在这里要问的是,假设在res.render上,我确实想立即返回所有这些信息,还有什么比嵌套更好的东西了吗?干杯

推荐答案

您可以使用

You can get rid of nested database calls by using promises.

由于您提到您正在使用 mysql 库进行交互对于数据库,不幸的是,该库未提供基于诺言的API.因此,要摆脱代码中的嵌套数据库调用,您需要围绕数据库调用的回调版本创建一个基于promise的包装器.

Since you mentioned that you are using mysql library for interacting with the database, unfortunately, this library doesn't provides a promise-based API. So to get rid of nested database calls in your code, you need to create a promise-based wrapper around the callback version of database calls.

有关什么是承诺及其运作方式的一般概述,请参见以下链接:

For a general overview of what promises are and how they work, see the following links:

以下是如何创建基于promise的包装程序,然后使用该包装程序摆脱嵌套数据库调用的示例.

Following is an example of how you can create a promise-based wrapper and then use that wrapper to get rid of nested database calls.

这个基于promise的包装器只是一个返回promise的函数.它创建一个Promise实例,包装基础数据库调用,并最终在数据库调用返回数据时通知您的代码.

This promise-based wrapper is just a function that returns a promise. It creates a promise instance, wraps the underlying database call and eventually when the database call returns the data, it notifies your code.

function getCats() {
   return new Promise((resolve, reject) => {
       // make the database call
       db.cats((error, cats) => {
           // in case of an error, reject the promise by
           // calling "reject" function
           // Also pass the "error" object to the "reject" function
           // as an argument to get access to the error message 
           // in the code that calls this "getCats" function
           if (error) {
              reject(error);
              return;
           }
           
           // if there was no error, call "resolve" function
           // to resolve the promise. Promise will be resolved 
           // in case of successful database call
           // Also pass the data to "resolve" function
           // to access this data in the code that calls this
           // "getCats" function
           resolve(cats);
       });
   });
}

现在在路由处理程序函数中,而不是调用 db.cats(...),而是调用此 getCats 包装函数.

Now to in your route handler function, instead of calling db.cats(...), call this getCats wrapper function.

您可以通过两种方式调用返回承诺的函数:

There are two ways you can call the function that returns a promise:

  • 承诺链(有关详细信息,请访问上面提到的链接)
  • async-await 语法(推荐)
  • Promise-chaining (For details, visit the links mentioned above)
  • async-await syntax (Recommended)

以下代码示例使用 async-await 语法.为此,首先在 function 关键字之前使用 async 关键字将路由处理程序功能标记为 async .为此,我们可以在此路由处理函数中使用 await 关键字.

Following code example uses async-await syntax. For this, first mark the route handler function as async by using the async keyword before the function keyword. Doing this, we can use await keyword inside this route handler function.

app.get('/pets', async function(req, res, next) {
    try {
       const cats = await getCats();
       // similar wrappers for other database calls
       const dogs = await getDogs();
       const budgies = await getBudgies();
       
       // render the pub template, passing in the data
       // fetched from the database 
       ...

     catch (error) {
       // catch block will be invoked if the promise returned by
       // the promise-based wrapper function is rejected
       // handle the error appropriately
     }
});

以上代码示例仅显示如何在基于Promise的包装器中包装 db.cats(...)数据库调用,并使用该包装器从数据库中获取数据.同样,您可以为 db.dogs(...) db.budgies(...)调用创建包装器.

Above code example only shows how to wrap the db.cats(...) database call in a promise-based wrapper and use that wrapper to get the data from the database. Similarly, you can create wrappers for db.dogs(...) and db.budgies(...) calls.

理想情况下,您应该创建一个可重用的基于promise的包装函数,该函数接受一个要调用的函数并包装该函数调用,而不是为每个数据库调用创建一个单独的基于promise的包装器就像上面的代码示例中所示的那样,即 getCats 函数.

Instead of creating a separate promise-based wrapper for each database call, ideally, you should create a re-usable promise-based wrapper function that takes in a function to call and wraps that function call in a promise just like shown in the above code example, i.e. getCats function.

在上面的代码中,路由处理程序函数中要注意的一件事

One important thing to note in the above code in the route handler function

const cats = await getCats();
const dogs = await getDogs();
const budgies = await getBudgies();

是因为这将导致顺序数据库调用,这可能与您想要的不一样.

is that this will lead to sequential database calls which may or may not what you want.

如果这些数据库调用互不依赖,则可以使用

If these database calls do not depend on each other, then you can call the promise-based wrappers in parallel using Promise.all() method.

下面的代码示例演示如何使用 Promise.all()并行调用基于promise的包装函数.

Following code example shows how you can call your promise-based wrapper functions in parallel using Promise.all().

app.get('/pets', async function(req, res, next) {
    try {
       // "petsData" will be an array that will contain all the data from 
       // three database calls.
       const petsData = await Promise.all([getCats(), getDogs(), getBudgies()]);
       
       // render the pub template, passing in the data
       // fetched from the database 
       ...
 
     catch (error) {
       ...
     }
 });

我希望这足以帮助您摆脱当前代码中的嵌套数据库调用,并开始在代码中使用promise.

I hope this is enough to help you get rid of the nested database calls in your current code and start using promises in your code.

这篇关于取消嵌套节点数据库调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆