javascript - 避免nodeJs中的回调 hell /将变量传递给内部函数

标签 javascript node.js express callback mongoose

这是我想简化的示例:

exports.generateUrl = function (req, res) {
    var id = req.query.someParameter;

    var query = MyMongooseModel.findOne({'id': id});
    query.exec(function (err, mongooseModel) {
        if(err) {
            //deal with it
        }

        if (!mongooseModel) {
            generateUrl(Id,
                function (err, text, url) {
                    if (err) {
                        res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
                        return;
                    }
                    var newMongooseModel = new AnotherMongooseModel();
                    newMongooseModel.id = id;

                    newMongooseModel.save(function (err) {
                        if (err) {
                            res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
                        } else {
                            res.send({url: url, text: text});
                        }
                    });
                });
        } else {
            //deal with already exists
        }
    });
};

我看过其他 SO 答案,他们告诉您使用命名函数,但没有说明如何处理要传入的变量或使用 jQuery 的队列。我两者都没有。

我知道我可以用命名函数替换我的匿名函数,但是我需要传递周围的变量。例如,如果函数在别处定义,我的内部函数将如何访问 res

最佳答案

你的问题的核心是:

I understand that I can replace my anonymous functions with names functions, but then I would need to pass arounds variables. How would my inner function access res for instance if the function is defined elsewhere?

答案是使用函数工厂。

一般来说,这是:

function x (a) {
    do_something(function(){
        process(a);
    });
}

可以转换成这样:

function x (a) {
    do_something(y_maker(a)); // notice we're calling y_maker,
                              // not passing it in as callback
}

function y_maker (b) {
    return function () {
        process(b);
    };
}

在上面的代码中,y_maker 是一个生成函数的函数(我们称该函数的用途为“y”)。在我自己的代码中,我使用命名约定 .._makergenerate_.. 来表示我正在调用函数工厂。但这只是我的看法,这个约定绝不是标准的,也不是在野外广泛采用的。

因此对于您的代码,您可以将其重构为:

exports.generateUrl = function (req, res) {
    var id = req.query.someParameter;

    var query = MyMongooseModel.findOne({'id': id});
    query.exec(make_queryHandler(req,res));
};

function make_queryHandler (req, res) {
    return function (err, mongooseModel) {
        if(err) {
            //deal with it
        }
        else if (!mongooseModel) {
            generateUrl(Id,make_urlGeneratorHandler(req,res));
        } else {
            //deal with already exists
        }
}}

function make_urlGeneratorHandler (req, res) {
    return function (err, text, url) {
        if (err) {
            res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
            return;
        }
        var newMongooseModel = new AnotherMongooseModel();
        newMongooseModel.id = id;
        newMongooseModel.save(make_modelSaveHandler(req,res));
}}

function make_modelSaveHandler (req, res) {
    return function (err) {
        if (err) res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
        else res.send({url: url, text: text});
}}

这使嵌套回调变平。作为一个额外的好处,您可以正确命名函数应该做什么。我认为这是很好的做法。

它还有一个额外的优势,它比使用匿名回调要快得多(无论是使用嵌套回调还是使用 promise,尽管如果您将命名函数传递给 promise.then() 而不是匿名函数,那么您将获得同样的加速 yield )。之前的一个 SO 问题(我的 google-fu 今天让我失望了)发现命名函数的速度是 node.js 中匿名函数的两倍多(如果我没记错的话,它快了 5 倍多)。

关于javascript - 避免nodeJs中的回调 hell /将变量传递给内部函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25941010/

相关文章:

javascript - 通过 Node.js 将 base64 编码的图像上传到 Amazon S3

node.js - Nodejs- Req.body 在 express 4.x 的帖子中未定义

mysql - Sequelize 抛出错误 "must be unique"

javascript - 如何在 ejs 脚本部分使用后端变量?

javascript - React 复选框 - Onchange 复选框,第一次未定义

php - 通过回显将日期时间/时间戳从 PHP 传递到 Javascript

javascript - 严格模式变更的规则是什么?

node.js - 来自 Graph 的 base64 转换照片显示为损坏的图像

javascript - 将本地 mp4 文件转换为 fileURL 以进行视频 react

javascript - 计算覆盖双直径圆的圆的坐标