2

我正在尝试为即将到来的项目选择一个 JS 模板引擎,而我最喜欢的一个似乎是dust.js。

我喜欢它是异步的想法,即我只是为渲染准备一些模板,当它准备好时,回调将渲染的 HTML 插入到 DOM 中。

但是我不确定如何解决同步回调中​​的异步渲染问题。例如 - 我经常使用DataTables插件,它提供了一些回调,允许我在实际插入 DOM 节点之前修改它们。

为了说明这个问题 - 让我们假设我有一个以下片段(从DataTables website获取和修改):

$(document).ready( function() {
  $('#example').dataTable( {
    "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
      // modify the node before it's actually inserted into the document
      $('td:eq(4)', nRow).html( '<b>' + aData[4] + '</b>' );
    }
  } );
} );

现在-我想摆脱'<b>' + aData[4] + '</b>'并使用带有某些上下文的模板来代替(这是一个微不足道的示例,但显示了问题)。

如果我理解正确,我不能强制dust.js同步渲染模板,因此可能会发生未处理的节点将被插入到文档中(用户会看到它未处理),然后在dust.js实际渲染模板时,该节点将被修改.

从用户的角度来看,这显然看起来不太好。

那么真的是这种情况(dust.js不能强制同步),如果是的话 - 如何应对?我应该使用同步引擎吗,handlebars或者mustache我在这里看不到明显的东西?

非常欢迎任何帮助、见解或建议。谢谢!:)

编辑:

这个问题不是关于如何渲染模板,而是关于如何确保它在fnRowCallback完成之前被渲染。感谢@robertklep 用您的(已删除)答案指出这一点。

4

1 回答 1

-2

编辑:要清楚,我认为这是一个不好的做法,你通常不应该做这样的事情。我将下面的代码仅作为一个示例,说明如果技术或架构限制迫使您这样做,一个人如何做这样的事情。但是,它只能作为最后的手段使用。

我过去做过一些令人讨厌的事情,涉及使用布尔值和循环来“捕获”异步调用,但我不会真的推荐它作为一个特别好的做法。不过,如果你想要它,它就在这里。

// name is the template identifier, template is the template contents,
// data is the "context" of the template (its model), callback (optional)
// is the method you want the rendered template passed to, cbContext
// (optional) is the context in which you want the callback to execute
asyncToSync = function (name, template, data, callback, cbContext) {
    // Tracks if it's time to return or not
    var finished = false;
    // Gives us an exit condition in case of a problem
    var maxLoops = 10000;
    // Create a variable to store the return value
    var outVal = 'Template rendering did not finish';
    // And the callback function to pass to dust
    var dustCb = function (err, html) {
        finished = true;
        outVal = html;
    }
    var i = 0;
    // We create this as a function so that increment goes to the bottom
    // of the execution queue, giving dustCb a chance to execute before
    // the counter hits max.
    var incrementCounter = function () {
        i += 1;
    };
    // Compile, load, and render the template
    var compiled = dust.compile(template, name);
    dust.loadSource(compiled);
    // Pass our callBack so the flag gets tripped and outVal gets set
    dust.render(name, data, dustCb);
    // count up to maxLoops
    while(!finished && (i < maxLoops)) {
        incrementCounter();
    }
    // If a callback is defined, use it
    if (callback) {
        // If a callback context is defined, use it
        return (cbContext) ? callback.call(cbContext, outVal) : callback(outVal);
    }
    // otherwise just return the rendered HTML
    return outVal;
}
于 2013-04-18T00:12:42.810 回答