能否同步渲染dust.js模板?

19

我正在尝试为客户端HTML/JS模板系统编写适配器,以便在其内部使用dust.js。不幸的是,该API期望呈现操作同步发生:呈现的输出应从render()调用中返回。Dust.js是异步的,并将呈现输出传递给回调函数。是否有办法解决这个问题,可以通过Dust APIs或通过一些疯狂的Javascript hack来实现?


1
好问题!我也想知道同样的事情,因为我想在CouchDB“show”函数(服务器端)中使用dust.js。 - Nick Perkins
不幸的是,consolidate.js 提供的 API 使用了与 dust.js 相同的回调函数,因此我认为它在这里没有帮助 :/ - cliff.meyers
3个回答

16
DustJS只会在需要渲染的资源(模板、局部)尚未全部加载时异步执行。如果在执行模板之前已经加载了模板的所有依赖项,则它将同步执行(至少我这样认为)。因此,您可以执行以下操作:
var result;
dust.render("tpl", data, function(err, res) {
   result = res;
});
console.log(result); // result will actually already be filled out if dustjs didn't
// have to go look for resources somewhere.

以下是更详细的示例: (这里有一个jsfiddle链接,您可以在该链接上运行代码:http://jsfiddle.net/uzTrv/1/

<script type="text/javascript" src="dust.js"></script>
<script>
    var tpl = dust.compile("Omg {#people} {.} {/people} are here! {>partial/}", "tpl");
    var partial = dust.compile("I'm a partial but I've already been included so things still run {how}", "partial");
    dust.loadSource(tpl);
    dust.loadSource(partial);

    var data = {
        people: ["jim", "jane", "jack", "julie"],
        how: "synchronously!"
    };

    var result;
    dust.render("tpl", data, function(err, res) { 
        result = res;
    });
    console.log(result);
</script>

除了我提到的那种情况,可能还有其他情况我是错的... 我并不是对dustjs了解的非常全面。


验证通过。这个可以工作,但是你必须非常小心,不要做任何会让模板决定异步执行的事情。 - heneryville
4
警告:dust.onload(可用于延迟加载模板/局部文件)不是唯一的异步操作。您 JSON 数据中的任何自定义帮助器或函数也可以通过调用 chunk.map 并进行 ajax 调用、setTimeout 等异步运算。因此,这绝对不是一个完整的解决方案。 - Yevgeniy Brikman

2
我也想要一个接受上下文并返回渲染后的dust文本的函数。这是我想出来的解决方案:
// This function sets up dust template, and returns a new function "dusterFn()"
// dusterFn() can be passed a Context, and will return the rendered text.
// @param {String} text: The template text.
// @param {String} [name]: The name of the template to register with dust. If none is provided, a random number is used.
// @param {Function} [onError]: A function that is called if an error occurs during rendering.
function getDusterFn(text, name, onError) {

    var dusterFn = null;
    name = name || Math.floor(Math.random() * 99999).toString();
    onError = onError || function (error) { };

    try {

        var compiled = dust.compile(text, name)
        dust.loadSource(compiled);

        dusterFn = function (context) {
            var dustOutput = '';
            dust.render(name, context, function (error, out) {
                if (error) onError(error);
                dustOutput = out;
            });
            return dustOutput;
        };

    } catch (e) {
        // invalid template syntax 
        e += "\n\nPlease check your template syntax.";
        throw (e);
    }

    return dusterFn;

}

使用方法

var greetingTemplate = getDusterFn('Hello {name}, You are {age} years old!');
greetingTemplate({name: 'Jane', age: 24});

0

Matt的解决方案给了我一些指针,告诉我如何编写一个小包装器来隐藏他的解决方案的“丑陋”(所谓的“丑陋”是指在回调外部声明变量,在回调内部分配值并在回调外部返回)。

它不仅将这个hack封装成一个小函数,还绑定了模板的名称。我发现这非常有帮助,因为我经常使用相同的渲染函数,但我不想每次都指定模板的名称。

function templates(template) {
  return function templatesWrapper(data) {
    var result;
    dust.render(template, data, function onRender(err, data) {
      if (err) {
        throw err;
      }
      result = data;
    });
    return result;
  }
}

这是如何使用它的:

var renderHello = templates('hello.html');
renderHello({ username: 'Stackoverflow' });
// => <h1>Hello, Stackoverflow</h1>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接