在ExpressJS中使用promises,把手和中间件

时间:2017-03-03 16:59:49

标签: node.js express promise handlebars.js

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

<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值为“undefined”:

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. 如果承诺被拒绝怎么办?
  4. 谢谢。

1 个答案:

答案 0 :(得分:1)

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

因此,您只想在中间件中完成工作并且所有内容都设置为呈现(或链中的下一个中间件)时调用next()

  

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

如果某些事情发生了有效而其他事情没有发生,那么你可能只是陷入了平局的运气中。时间问题。当您不等待调用next()时,您将在异步操作和渲染中涉及的其他异步操作之间创建竞争。由于这些类型的比赛是不可预测的,它可能会起作用,它可能不起作用,或者它的某些部分可能起作用。使用正确代码的想法是删除所有种族,因此它始终有效。

  

保持&#34; next()&#34;会有什么影响?承诺回调中的声明?

它所属的位置(在promise回调中),用于正确和可预测的执行。只有当回调执行时,您才真正为渲染的后续步骤准备好所有内容,这样才能调用next()并继续路由。

  

如果承诺被拒绝怎么办?

你必须有一个拒绝处理程序,并决定适当的响应是什么。如果将next()放在它所属的.then()处理程序中并且您没有拒绝处理程序,那么您的请求将永远不会发送响应,最终浏览器将超时。您需要一个.catch()处理程序,它可能返回500类型的错误页面。您可以调用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!')
});