假设我们想使用Pug和NodeJS创建一个网页,显示一个基于外部数据源的项目列表,例如:。
doctype html
...
body
p Welcome to #{siteName}
each item in variableWithExternalData
ul
li= item
当前的方法:
data
res.render('index', {siteName: 'MyName', variableWithExternalData: data});
虽然这样做很好,但它并不是特别迅速的客户端体验,因为服务器首先要处理外部数据,然后再渲染页面。更为可取的是像下面这样。
这将是有益的,因为在检索和处理外部数据之前,页面可以呈现,特别是由于该 ul
在页面加载时,并不直接可见。我知道可以通过使用Ajax从客户端发出请求,然后使用JavaScript将项目添加到列表中,从而实现类似上述的功能。然而,我想知道是否有一种Pug允许的更基于服务器端的方法,例如在 pug.render()
?
你可以发送部分页面(HTML标记),使用分块响应,然后在后端处理更多的数据后,再发送另一个页面的分块。不过这种方式有一定的局限性,你不能在已经发送的数据中间插入内容。
至于Pug,它是模板库,与发送数据回客户端无关。你可以用Pug来创建整个页面的HTML,或者只创建其中的一部分。然后根据你的意愿从Pug中发送输出。
下面我写了简单的NodeJS演示,展示了分块发送HTML。每秒钟都会有新的分块发送。10个chunks之后,将发送结束标签。每一个分块都应该在到达后立即在浏览器中呈现。
const http = require('http')
const port = 3000
const hostname = 'localhost'
const server = http.createServer(main)
function main (req, res) {
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
res.setHeader('Transfer-Encoding', 'chunked')
let chunksLeft = 10
res.write('<DOCTYPE html><html><head><title>Chunked response demo</title></head><body>')
res.write(`<h1>Hello chunks!</h1><p>I will be sending ${chunksLeft} entries.</p><ol>`)
function sendChunk () {
chunksLeft -= 1
res.write(`<li>Entry</li>`)
if (chunksLeft > 0) {
setTimeout(sendChunk, 1000)
} else {
res.end('</ol></html>')
}
}
sendChunk()
}
function message () {
console.log(`Listening on ${hostname}:${port}...`)
}
server.listen(port, hostname, message)
下面的代码展示了使用 axios 和 pug 库从外部 API 获取和渲染数据,使用了前面例子中的概念。
const http = require('http')
const axios = require('axios')
const pug = require('pug')
const port = 3000
const hostname = 'localhost'
const server = http.createServer(main)
const template =
`doctype html
html
head
title Chunked response with pug and axios
body
h1 Hello chunks!
p Below is example data downloaded from <a href="https://jsonplaceholder.typicode.com/todos">jsonplaceholder</a> and transformed to HTML.`
const list =
`ol
each t in todos
li= t.title`
function main (req, res) {
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
res.setHeader('Transfer-Encoding', 'chunked')
res.write(pug.render(template))
axios.get('https://jsonplaceholder.typicode.com/todos').then(reply => {
res.end(pug.render(list, { todos: reply.data }))
}).catch(() => {
res.end(pug.render('p Error: could not download todos!'))
})
}
function message () {
console.log(`Listening on ${hostname}:${port}...`)
}
server.listen(port, hostname, message)
更多信息。