2012-03-24 18 views
19

Estoy tratando de escribir un adaptador para un sistema de plantillas HTML/JS del lado del cliente para usar dust.js bajo el capó. Lamentablemente, la API espera que las operaciones de representación se produzcan de forma síncrona: la salida representada debe devolverse desde la llamada a render(). Dust.js es asíncrono y pasa la salida de renderizado a una función de devolución de llamada. ¿Hay alguna forma de evitar esto, ya sea en las API de polvo o a través de algún truco loco de Javascript?¿Es posible renderizar las plantillas dust.js sincrónicamente?

+1

Buena pregunta! Quiero saber lo mismo porque quiero usar dust.js en una función "show" de CouchDB (lado del servidor). –

+0

¿Consolidate.js ayuda? – sntran

+0

Desafortunadamente, parece que la API que ofrece consolidate.js usa una función de devolución de llamada de la misma forma que dust.js, por lo que no creo que ayude aquí:/ –

Respuesta

16

DustJS solo ejecutará cosas de forma asíncrona cuando los recursos que necesita representar (plantillas, parciales) no se hayan cargado todavía.

Si todas las dependencias de una plantilla se cargan antes de ejecutar esa plantilla, se ejecutará de forma síncrona (hasta donde sé de todos modos). Así que usted puede hacer algo como:

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. 

Aquí es un ejemplo más completa a continuación: (y aquí hay un enlace jsFiddle para que pueda ejecutarlo: 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> 

puede haber casos (además el que mencioné) donde estoy equivocado ... No sé todo sobre dustjs.

+0

verificado. Esto funciona, aunque debes tener mucho cuidado de no hacer nada que haga que la plantilla decida sincronizarse. – heneryville

+4

Una advertencia: dust.onload (que se puede usar para cargar plantillas/parciales de carga lenta) no es lo único que puede ser asincrónico. Cualquier ayuda o funciones personalizadas en sus datos JSON también pueden ser asincrónicas llamando a chunk.map y luego haciendo una llamada ajax, setTimeout, etc. Por lo tanto, definitivamente esta no es una solución de prueba completa. –

2

Yo también quería tener una función que aceptara un contexto y devolviera el texto generado. Aquí está la solución que se me ocurrió:

// 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; 

} 

Uso

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

solución de Matt me dio algunos consejos sobre cómo escribir un pequeño envoltorio que oculta la "fealdad" de su solución (por "fealdad" me refiero a declarar una variable fuera de la devolución de llamada, asignar valor dentro de la devolución de llamada y devolver la devolución de llamada externa).

No solo envuelve el truco en una pequeña función sino que también vincula el nombre de la plantilla. Encuentro esto increíblemente útil ya que me encuentro usando la misma función de renderizado una y otra vez, pero no quiero especificar el nombre de la plantilla cada vez.

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; 
    } 
} 

Esto es cómo usarlo:

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