【问题标题】:Best way to pass route params between callbacks in expressjs在expressjs中的回调之间传递路由参数的最佳方法
【发布时间】:2016-09-07 11:07:53
【问题描述】:

我试图在这里搜索类似的问题,但令人惊讶的是找不到已经发布的问题。

我使用 expressjs v4 框架,我正在构建这样的路线:

'use strict';

let express = require('express');
let router = express.Router();
let users = require('./modules/users');

router.post('/',users.add);

router.put('/edit/:id',users.edit);

正如你在上面看到的,我需要let users = require('./modules/users')

现在users 模块看起来(假设)如下:

'use strict';
let usersDbModule = require('...');

let users = {
    'add': (req, res, next) => {
         let callback = (err, record) => {
            //...do something
            users.function1(record)
         }
         usersDbModule.save(req, callback);
    },
    'function1': (record) => {
         users.function2()
    },
    'function2': () => {
         //...do something with next() function
    }
}

您可以注意到,第一个代码块中的路由器正在使用模块的add 函数。 add 函数,它是一个标准的 express 中间件函数,但现在事情变得越来越复杂了。

如您所见,add 函数将next 作为参数之一,现在我正在执行来自不同函数的一些复杂回调调用,假设最后我想在@ 中调用next 987654330@.

我的问题是,在同一模块内的不同回调函数之间传递 reqresnext 参数的最佳方式是什么。

我想出了 3 种不同的方法:

方法一: 如有必要,将reqresnext 传递给链中的所有函数,因此在这种情况下,我必须将next 传递给callback,而不是传递给function1,而不是从function1 传递给function2.

在我看来,这不是最好的方法,难以维护、阅读和测试。

方法二:function1function2 包裹在 add 中的闭包中,传递所有必要的参数。在这种特殊情况下,我只需要包装 function2 并通过 next 闭包,所以它看起来像这样:

'add': (req, res, next) => {
    users.function2(next);
    //....rest of the code of the function add
}

function2 本身:

'function2': (next) => {4
   return () => {
       //...now I have access to next here
       // without a need to pass it to each and every
       // function in the chain
   }
} 

方法三:

将所有必要的函数/变量附加到res.locals 并仅传递res 对象。

它与Method 1 有完全相同的问题,所以我个人赞成Method 2,但不确定它是否不会降低代码的可读性,也许还有其他一些问题,没有与团队一起在生产或开发环境中对其进行了测试。


我真的很想听听你们在使用什么以及它在您的项目/团队中的作用。任何偏好、最佳实践、最佳模式?请分享,我真的很想知道什么是最好的方法。

也许有更好的方法?

非常感谢所有反馈!


现实生活中的例子:

function1function2 以及可能更多的示例用法...

假设我们有一个从外部 API 获取数据的适配器,它需要将数据保存到数据库中并返回响应。我们还假设从 API 返回的数据在 5s 后过期。如果客户端在 5 秒内到达路由,它会从数据库中获取数据,如果调用之间的时间较长,则它会重复调用 API 的操作。

这当然比function1function2 更复杂。它需要来自适配器和数据库的大量回调函数,还需要从数据库中获取数据,适配器,将数据保存到数据库中以及最终从数据库中删除数据的单独函数,它至少提供4个回调函数已经。

【问题讨论】:

    标签: javascript node.js express callback


    【解决方案1】:

    我认为混合 express 和应用程序逻辑不是一个好主意。 我在我的项目中使用下一种方式

    // middlewares/auth.js
    // Example middleware
    exports.isAdmin = function (req, res, next) {
        if (smth-admin-check)
            next();
        else
            next (new Error(403));
    }
    
    // routes/index.js
    // Include only modules from /routes
    let user = require('./user');
    let auth = require('../middlewares/auth');
    ...
    app.get('/user/:id(\\d+)', user.get);
    app.post('/user', auth.isAdmin, user.post); // only admin can add user
    
    // routes/user.js
    // Call model methods and render/send data to browser
    // Don't know about db 
    let User = require('/models/user');
    ...
    exports.get = function(req, res, next) {
        let id = req.params.id;
        // I cache most data in memory to avoid callback-hell
        // But in common case code like below 
        User.get(id, function(err, u) {
            if (!u)
                return next(new Error('Bad id'));
    
            ... render page or send json ...
        });
    }
    ...
    exports.post = function(req, res, next) { ... } 
    
    // models/user.js
    // Encapsulate user logic
    // Don't use any express features 
    let db = require('my-db');
    ...
    class User {
       get(id, callback) { ... } 
       add(data, callback) { ... } // return Error or new user
       ...
    }
    

    【讨论】:

    • 您在哪里看到混合了逻辑和快速路由?它是分开的,users.add 函数是路由的callback,所以router.post('/',users.add); 是我将应用程序特定逻辑与快速路由分开的确切位置。此外,您的回答并没有解决问题,您的示例是完全跳过function2 问题的超级简单版本。
    • 您能否提供function1function2 的用途示例?
    • 刚刚更新了分析器,在最底部给出了一个示例。谢谢
    • 我认为更好的方法是将提取数据的逻辑下推到模型中。所以 Express 将有一个简单的回调函数来获得如上所示的结果。
    猜你喜欢
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-30
    • 2017-01-10
    • 1970-01-01
    相关资源
    最近更新 更多