【问题标题】:Using promises, handlebars and middleware in ExpressJS在 ExpressJS 中使用 promises、handlebars 和中间件
【发布时间】:2017-07-23 21:35:40
【问题描述】:

我有一个车把模板,其中包含两个部分和一个从上下文填充的数据。

<h1>Welcome to {{title}}</h1>
<div id="views">
    <div id="place">{{> place}}</div>
    <div id="player">{{> player}}</div>
</div>

现在在 ExpressJS 路线上,我正在执行以下操作:

var express = require('express');
var router = express.Router();

var gameDal = require('../app/DAL/gameRepository');

router.use('/', (req, res, next) => {
    if(!res.locals.gameContext) res.locals.gameContext = {};

    gameDal.getGame(0).then(game => {
        res.locals.gameContext.player = game.player;
        res.locals.gameContext.place = game.place;
        req.gameTitle = game.title;
        next();
    });
});

router.get('/', (req, res) => {
    res.render('home', { "title": req.gameTitle });
});

module.exports = router;

代码按预期工作,但如果我从“then”回调中取出“next()”语句,则两个部分都将正确填充接收到的数据,但“gameTitle”值未定义。

换句话说,以下内容不会替换模板中的 {{title}} 值,因为在渲染模板时,req.gameTitle 值是“未定义”:

router.use('/', (req, res, next) => {
    if(!res.locals.gameContext) res.locals.gameContext = {};

    gameDal.getGame(0).then(game => {
        res.locals.gameContext.player = game.player;
        res.locals.gameContext.place = game.place;
        req.gameTitle = game.title;
    });

    next();
});

所以我的问题是:

  1. 为什么部分填充了数据而包含模板没有填充?
  2. 将“next()”语句保留在 Promise 回调中会有什么影响?
  3. 如果承诺被拒绝怎么办?

谢谢。

【问题讨论】:

    标签: node.js express promise handlebars.js


    【解决方案1】:

    next() 允许路由继续。如果您在正确填充res.locals 之前允许该路由继续,则渲染可能会在设置这些值之前发生。那显然是错误的。

    因此,当您的工作在中间件中完成并且一切都设置好渲染(或链中的下一个中间件)时,您只想调用 next()

    为什么部分是用数据填充的,而包含的模板却不是?

    如果有些事情发生了,而有些事情却没有,那么您可能只是遇到了“抽签运气”的时间问题。当您迫不及待地打电话给next() 时,您将在异步操作和渲染中涉及的其他异步操作之间产生竞争。由于这些类型的比赛是不可预测的,它可能会起作用,它可能不会起作用,或者它的某些部分可能起作用。正确代码的想法是删除所有种族,因此它始终有效。

    将“next()”语句保留在 Promise 回调中会有什么影响?

    这就是它所属的地方(在 Promise 回调中),以便正确且可预测地执行。只有当该回调执行时,您才能真正为接下来的渲染步骤做好一切准备,因此只有在那时您才应该调用 next() 并继续路由。

    如果承诺被拒绝怎么办?

    您必须有一个拒绝处理程序并决定正确的响应是什么。如果您将next() 放在它所属的.then() 处理程序中,并且您也没有拒绝处理程序,那么您的请求将永远不会发送响应,最终浏览器将超时。您需要一个可能返回 500 类型错误页面的 .catch() 处理程序。您可以调用next(err),其中err 是某种错误,然后您可以拥有一个通用的错误处理中间件,该中间件将提供错误页面。有关使用 Express 进行一般错误处理的信息,请参阅此答案:

    Error Handlers in Express

    例如,您可以这样做:

    router.use('/', (req, res, next) => {
        if(!res.locals.gameContext) res.locals.gameContext = {};
    
        gameDal.getGame(0).then(game => {
            res.locals.gameContext.player = game.player;
            res.locals.gameContext.place = game.place;
            req.gameTitle = game.title;
            next();
        }).catch(err => {
            next(err);
        });
    
    });
    
    // Generic error handler for express - should be last middleware defined
    // on app object
    // Note that this has four arguments compared to regular middleware that
    // has three arguments
    // This will handle the next(err) call
    app.use(function (err, req, res, next) {
      console.error(err.stack)
      res.status(500).send('Something broke!')
    });
    

    【讨论】:

    • @SergioRomero - 这回答了你的问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 2019-01-12
    • 2018-09-11
    • 2021-09-06
    相关资源
    最近更新 更多