问题
I want to call some of my functions which are asynchronous to be called from within my ejs files.
Like I have this functions set as my app.locals.someFunction
async someFunction(param){
let data = await someAsyncStuff();
// & other things
return data;
}
and I want to use it inside ejs file as below:
<%
let data = await someFunction()
for(let x of data){%>
<li><%=x%></li>
<%}%>
This is possible with ejs if {async:true}
is passed as an option. But where exactly should I pass this when my view engine setup is like the following?
//view engine setup
app.engine ('.html', ejs.renderFile);
app.set ('view engine', 'html');
回答1:
instead res.render()
const ejs = require('ejs');
const html = await ejs.renderFile(view, data, {async: true});
res.send(html);
every include with await
<body>
<%- await include(pageView);%>
</body>
async now fine
<%
let data = await collection.find().toArray();
for(let x of data){%>
<li><%=x%></li>
<%}%>
回答2:
You have to pass the argument async into your render() function call as opts. E.g.
res.render(view, {.., async:true, ... }...)
回答3:
For people who are still trying to figure out how to implement async ejs templates, I am listing my complete solution below:
In your main app file (app.js)
// app.js
// Set ejs as view engine
app.set('view engine', 'ejs');
let ejsOptions = {
// delimiter: '?', Adding this to tell you do NOT use this like I've seen in other docs, does not work for Express 4
async: true
};
// The engine is using a callback method for async rendering
app.engine('ejs', async (path, data, cb) => {
try{
let html = await ejs.renderFile(path, data, ejsOptions);
cb(null, html);
}catch (e){
cb(e, '');
}
});
Now for your route responses...
app.route('/login')
.get( async (req, res) =>{
// layout.ejs is my version of blocking. I pass the page name as an option to render custom pages in the template
return await res.render(`layout.ejs`, { page : 'login' }, (err, html) => standardResponse(err, html, res));
})
I user the function standardResponse() in the callback for both readability and so I have to write less lines. The function works like this...
const standardResponse = (err, html, res) => {
// If error, return 500 page
if (err) {
console.log(err);
// Passing null to the error response to avoid infinite loops XP
return res.status(500).render(`layout.ejs`, { page : '500', error: err }, (err, html) => standardResponse(null, html, res));
// Otherwise return the html
} else {
return res.status(200).send(html);
}
}
And viola! Asynchronous ejs rendering.
来源:https://stackoverflow.com/questions/60203249/ejs-async-true-with-node-express