使用 Keystone View 进行 Nunjucks 异步渲染

Nunjucks Async Rendering with Keystone View

在基于 Express 的应用程序中,我是 运行 一个异步函数,用于从数据库中获取图像源并将它们渲染到 Nunjucks 视图引擎中

Nunjucks 正在 DOM

中呈现以下内容
<img src="[object Promise]">

我已经enabled Nunjucks's async rendering with web: { async: true } and enabled the nunjucks async api with a callback喜欢

// controller.js (KeystoneJS app)
view.render('index', function (err, res) {
    console.log('err at index render', err); // undefined
    return res;
});

如何获取异步函数的解析值?

据我了解,Nunjucks 不直接支持异步渲染。您可以使用异步过滤器来获取它。也许我错了。

恕我直言,使用带有 Be Careful! 标记的功能不是个好主意。


// template.njk
Hello {{user_id | find | attr('name') }}!

// app.js
var nunjucks  = require('nunjucks');
var env = nunjucks.configure();

// Async filter
env.addFilter('find', function(a, cb) {
    setTimeout(function () {
        cb(null, {
            name: 'Smith'
        });
    }, 10);
}, true)

// Sync filter
env.addFilter('attr', function(obj, attr) {
    return obj && attr && obj[attr];
});

env.render('template.njk', 
    {user_id: 1}, // pass sync vars
    function(err, res) {
        if (err)
           return;

        console.log(res);
        return res
    }
);

我不知道 nunjucks,但无论使用何种视图引擎,您都可以实现 async 功能。为了展示这个想法,我试着重现你的情况。我创建了一个名为 index.html 的 HTML 文件,带有 img 标签,没有任何 src 属性:

<html>
    <head>
        <meta charset="utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
        <title>Reproduce</title>
    </head>
    <body>
        <img id='bg'></img>
        <script src='./so.js'></script>
    </body>
</html>

我的 HTML 中有一个 <script> 标签,它链接到我的 so.js 文件,如下所示,通过向 NodeJS/Express 发送 HTTP 请求来请求图像服务器:

getImage();

function getImage(){

    // Get an image by its name as URL parameter
    fetch('/bg/background.jpg',{
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        }
    }).then(result=>{
        return result.blob()
    }).then(result=>{
        console.log('result -> ', result)
        document.querySelector('#bg').src=URL.createObjectURL(result)
        document.querySelector('#bg').style.width='200px'
    }).catch(err=>{
        console.log('err -> ', err)
    })
}

这是我的NodeJS/ExpressJS代码里面的一个文件名server.js:

express=require('express')
bodyParser=require('body-parser')
path=require('path')
fetch=require('node-fetch')

server=express()

//Body-parser middleware
server.use(bodyParser.json())
server.use(bodyParser.urlencoded({extended:false}))
server.use(bodyParser.raw())

//Set static path
server.use(express.static(path.join(__dirname,'public')))

server.get('/',(req,res)=>{
        res.render('index.html')
})

// Pick a file on hard disk
// and  send it as "Blob" to the browser
server.get('/bg/:name',(req,res)=>{
    var options = {
        root: __dirname + '/public/',
        dotfiles: 'deny',
        headers: {
            'x-timestamp': Date.now(),
            'x-sent': true
        }
    };

    var fileName = req.params.name;
    res.sendFile(fileName, options, function (err) {
        if (err) {
            next(err);
        } else {
            console.log('Sent:', fileName);
        }
    });
})

server.listen('8000',()=>{
        console.log('Server listening on port 8000...')
})

如您所见,我通过实现 fetch API 在浏览器和服务器之间进行 async 通信,甚至没有接触视图引擎。

我只是想提供一个替代想法 使用 fetch API 并与它进行 async HTTP 通信,而不管任何视图渲染引擎是正在使用。