如何在Express中的Node.js响应后退出? [英] How to exit after response in nodejs with express?

查看:76
本文介绍了如何在Express中的Node.js响应后退出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我第一次问有关stackoverflow的问题.抱歉,如果我发帖错误.

This is my first time asking a question on stackoverflow. Sorry if I made posting mistakes.

我试图在发送响应后退出功能,以防止继续执行该功能.

I am trying to exit a function after sending a response to prevent continuing through the function.

node -v = v12.6.0

node -v = v12.6.0

表达= ^ 4.17.1

express = ^4.17.1

猫鼬= ^ 5.6.6

mongoose = ^5.6.6

// handle adding a new book request submission
        addNewBook: function (req, res) {
            var response = null;
            var name = req.body.name.toLowerCase();
            var url = req.body.url.toLowerCase();
            var category = req.body.category.toLowerCase();
            var tags = req.body.tags.toLowerCase();
            // checking if category already exist. if not, make a new category
            Category.find({label: category}).exec(function(err, data) {
                if(err) {
                    response = res.status(400).send({message:'Error finding category.'});
                } else if(data.length === 0) {
                    var newCategory = new Category({label: category, description: '', keywords: ''});
                    newCategory.save(function(err, data){
                        if(err) {
                            response = res.status(400).send({message:'Error saving new category.'});
                        }
                    })
                }
            });
            // checking if book name already exist
            Book.find({name: name}).exec(function(err, data){
                if(err) {
                    response = res.status(400).send({message:'Error validating Book existence'});
                } else if(data.length > 0) {
                    response = res.status(200).send({message:'book name already exist'});
                } else {
                    req.body.name = name;
                    req.body.url = url;
                    req.body.category = category;
                    req.body.tags = tags;
                    // make a new book document
                    var newBook = new Book(req.body);
                    newBook.save(function (err, data) {
                        if (err) {
                            response = res.status(400).send({message: 'Error saving new Book.'});
                        } else {
                            response = res.json(data);
                        }
                    })
                }
            });

            return response;

        },

函数在返回后继续执行功能代码的其他部分.

Function continues to executes other part of the function code after a return.

在节点上,我也收到无法将标头发送到客户端后设置"错误.我想,阻止功能在发送响应后继续运行是否也可以解决此问题?

I am also getting "Cannot set headers after they are sent to the client" error on node. Im guessing, preventing the function to continue after sending a response will fix this as well?

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

推荐答案

逻辑流程存在两个问题.首先是 return 仅返回一个函数.它不会返回调用函数的函数或定义函数的函数.

There are two problems with the flow of your logic. First is that return only returns a function. It does not return the function that calls a function or the function that defines a function.

基本上,您的代码是:

Category.find({label: category}).exec(function(err, data) {
    if(err) {
        // ...
        return;
    } else if(/* ... */) {
        // ...
        newCategory.save(function(err, data){
            if(err) {
                // ...
                return;
            }
        })
    }
});

moreStuffDownHere();

// ...

让我们重写一下,不要使用匿名函数来清楚说明实际情况

Let's rewrite that to not use anonymous functions to make it clear what's really happening

function findCallback (err, data) {
    if(err) {
        // ...
        return; // it's obvious that this returns form findCallback()
                // and NOT yourFunction()
    } else if(/* ... */) {
        // ...
        newCategory.save(saveCallback);
    }
}

function saveCallback (err, data) {
    if(err) {
        // ...
        return;
    }
}

function yourFunction () {
    Category.find({label: category}).exec(findCallback);

    moreStuffDownHere();
}

因此,您现在可以看到您没有在 yourFunction()中的任何地方调用 return .

So you can now see that you are not calling return anywhere in yourFunction().

第二个问题是 Category.find().exec()是异步的.这意味着它会立即返回并允许其下面的任何代码在调用 findCallback()之前运行.要解决异步问题,只需在 findCallback()内移动 moreStuffDownHere().

The second problem is that Category.find().exec() is asynchronous. This means it returns immediately and let any code below it run before calling findCallback(). To solve the async issue just move moreStuffDownHere() inside findCallback().

因此,使程序流程正常运行的最简单的更改是移动 moreStuffDownHere :

Therefore, the simplest change to get your program flow working is to move moreStuffDownHere:

Category.find({label: category}).exec(function(err, data) {
if(err) {
        res.status(400).send({message: 'Error finding category.'});
        return;
    } else if(data.length === 0) {
        var newCategory = new Category({label: category, description: '', keywords: ''});
        newCategory.save(function(err, data){
            if(err) {
                res.status(400).send({message: 'Error saving new category.'});
                return;
            }

            // More stuff down here, that now will only execute if there are no errors
        })
    }
});


改善程序流程

上述解决方案的一个问题是,现在 moreStuffDownHere 已硬编码在保存回调中.解决它的一种方法是重构整个操作,并使其成为自己的内部API:


Improve program flow

One issue I have with the solution above is that now moreStuffDownHere is hardcoded inside the save callback. One way around it is to refactor the entire operation and make it your own internal API:

function addNewCategory (category, callback) {
    // callback will be passed status depending on success or failure

    Category.find({label: category}).exec(function(err, data) {
        if(err) {
            // ...
            callback('FIND_FAILURE');
            return;
        } else if(/* ... */) {
            // ...
            newCategory.save(function(err, data){
                if(err) {
                // ...
                    callback('SAVE_FAILURE');
                    return;
                }
                callback('OK');
            })
        }
    });
}

现在在 yourFunction()中,您可以检查整个操作的结果并决定返回还是继续:

Now inside yourFunction() you can check the result of the entire operation and decide to return or continue:

function yourFunction() {
    // ...

    addNewCategory(category, function (status) {
        switch (status) {
            case 'FIND_FAILURE':
                res.status(400).send({message: 'Error finding category.'});
                return;
            case 'SAVE_FAILURE':
                res.status(400).send({message: 'Error saving new category.'});
                return;
        }

        // More stuff down here ...
    });
}


改进2-承诺

通过使用Promises和async/await,可以使程序流更容易阅读.为此,您需要将操作包装在Promise中.我们可以使用上面编写的 addNewCategory 函数作为示例:

function addNewCategory (category) {
    // returns a Promise of true/false

    return new Promise(function (resolve, reject) {
      Category.find({label: category}).exec(function(err, data) {
        if(err) {
            // ...
            resolve('FIND_FAILURE'); // you can also use reject if you want
                                     // to use a try/catch flow
            return;
        } else if(/* ... */) {
            // ...
            newCategory.save(function(err, data){
                if(err) {
                // ...
                    resolve('SAVE_FAILURE');
                    return;
                }
                resolve('OK');
            })
        }
      });
   });
}

现在,代码变得更容易理解了,因为它使您可以将 moreStuffDownHere 保留在原来的位置,而无需将其移动到另一个函数中

Now the code is slightly easier to follow because it allows you to keep moreStuffDownHere where you originally have it without moving it inside another function:

async function yourFunction() {
    // ...

    var status = await addNewCategory(category);
    switch (status) {
        case 'FIND_FAILURE':
            res.status(400).send({message: 'Error finding category.'});
            return;
        case 'SAVE_FAILURE':
            res.status(400).send({message: 'Error saving new category.'});
            return;
    }

    // More stuff down here ...
}

注意:Express接受标记为异步的功能作为路由/中间件.您只需要照常调用 res.send() next()

这篇关于如何在Express中的Node.js响应后退出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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