当我们使用 Express 做服务端框架的时候,如果选择一种类似于 EJS这种模板引擎渲染前端页面的时候,经常服务端在响应 http 请求的时候调用 res.render({options})
去向模板中渲染数据。
我们还会经常看到 res.locals 和 app.locals 这对象,那么他们到底是干什么的呢? 查看原代码:
//express/lib/response.js
res.render = function render(view, options, callback) {
var app = this.req.app;
var done = callback;
var opts = options || {};
var req = this.req;
var self = this;
// support callback function as second arg
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge res.locals
opts._locals = self.locals;
// default callback to respond
done = done || function (err, str) {
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, opts, done);
};
变量 opts 初始时获得开发人员代码中传入的 options 对象,这段代码中的opts._locals = self.locals;
self 指向 res 对象自身,即又在最终渲染到模板中的变量里面增添了一个对象属性,该属性的值为 res.locals
紧接着调用到了 app.render
函数,并传入 opts 对象。
//express/lib/application.js
app.render = function render(name, options, callback) {
var cache = this.cache;
var done = callback;
var engines = this.engines;
var opts = options;
var renderOptions = {};
var view;
// support callback function as second arg
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge app.locals
merge(renderOptions, this.locals);
// merge options._locals
if (opts._locals) {
merge(renderOptions, opts._locals);
}
// merge options
merge(renderOptions, opts);
// set .cache unless explicitly provided
if (renderOptions.cache == null) {
renderOptions.cache = this.enabled('view cache');
}
// primed cache
if (renderOptions.cache) {
view = cache[name];
}
// view
if (!view) {
var View = this.get('view');
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
if (!view.path) {
var dirs = Array.isArray(view.root) && view.root.length > 1
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
: 'directory "' + view.root + '"'
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
err.view = view;
return done(err);
}
// prime the cache
if (renderOptions.cache) {
cache[name] = view;
}
}
// render
tryRender(view, renderOptions, done);
merge是一个很方便合并两个对象的第三方模块。
不难看出 这函数在得出最终的渲染变量对象的时候又再一次 merge了app.locals对象,将开发人员 res.render 传入的对象,res.locals 对象,app.locals 对象三者合并作为最终渲染模板的素材。
知道这个过程之后,很容易就能理解为什么经常在项目入口文件 app.js 中经常看到如下代码:
// 设置站点全局常量
app.locals.webGlobal = {
title: "",
description: "",
keywords: ""
}
// 设置可变但是又是每个模板总是需要的一些模板变量
app.use(function(req, res, next) {
res.locals._host = req.headers.host;
res.locals._user = req.user;
res.locals._url = req.url || req.originalUrl;
res.locals._moment = moment;
res.locals._enums = enums;
next();
});
res.render 传入的对象作为特定场景特定页面的个性化变量信息数据,app.locals
上通常挂载常量信息,res.locals
上通常挂载变量信息,三者相辅相成的共同构成渲染模板的整个变量信息。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。