-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for async templates using promises #11
Comments
This is extremely interesting, and I really want to discuss it more. Could you provide some more use cases? I can see the usefulness of the image example, but also find it confusing. Are you talking about client-side usage, or server-side? If you're talking about client side, then you might be better off using data-binding or model-binding. Given that server-side you'd need to use another node library like node-canvas or imagemagick, I'm not sure you'd want that much integration code in a helper. You might be better off doing it outside the template itself, and passing in actual image meta data instead of a path. Hence more examples would be super useful. But going on my current understanding of what you're looking for, I feel like what you want is actually possible right now, with two assumptions.
// in the template
@html.imgAsync( 'somepath.img', 'this is alt text' ) // the helper code, using the new-ish helper "instanced"
// version prototyped in the tplctx branch. `this.vo` is like the old
// __vo
Helpers.prototype.imgAsync = function( path, alt ){
this.asyncInit();
var mark = this.mark()
,self = this;
this.promises.push( somefunc.to.loadimgandreturnpromise( path )
.then(function( img ){
var after = self.fromMark( mark );
// `self.emit` is like `__vo.push` from previous versions
self.emit( '<img src="'
+ img.src + '" width="'
+ img.width + '" height="'
+ img.height + '" alt="'
+ self.escape( alt ) + '" />' );
self.emit( after );
}) )
}
Helpers.prototype.asyncInit = function(){
// ensure data properties
this.promises = this.promises || [];
this.promise = null;
}
Helpers.prototype.asAsync = function(){
if( this.promise ) return this.promise;
this.promises.unshift( this ); // add render context as first promise arg
this.promise = Q.all( promises );
return this.promise;
} // from your controller code or whatever
var tpl = vash.compile( tplStrl );
tpl( model ).asAsync().then( function( promises ){
// promises[0] should be the render context
// not 100% necessary, but this ensures you have the rendered
// string, otherwise coercion will... coerce it!
var rendered = promises[0].toString();
// do whatever you're going to do with it
// ....
} ) This code is untested, and just off my head, so no promises (cough) that it works. I could see integrating promises more into Vash's compiler, but I'd rather not have the hard dependency of a promise library. But having it as a dependency of a particular set of helpers is fine. The other concern of course is speed, which is hard to say if the hit of so many promises would be significant or not without benchmarks. |
My image example was just the simplest example I could think of. I meant that as server-side code. Passing the image info as metadata would require that the code that calls the view know which what images the view needs, which is IMHO wrong. You're right, though; most asynchronous operations do not belong in a view. This is not a feature I need right now, but it's a nice feature that I could envision needing in the future. Another use case would be embedding ASP.Net MVC-style partial views (reading the view file asynchronously) or child actions (which can be arbitrarily asynchronous) |
Yes, I can definitely see possible async actions/helpers. I'm going to leave this ticket open for now. |
Its possible use this.buffer.push(html)? |
I would ask a little differently, and I think it might be easier to implement. To add an option async:true that will make the compiled view to be async function instead of function, so we could use top level await within the template and call the compiled template function with await. Within html we will need to do |
Actually, I see that I must do, @await(myPromise()), perhaps I must modify some regex Where in the code is the render function generated? |
Use case:
Template:
Code:
It would be very nice to have an asynchronous version of Vash. I'd like to be able to call asynchronous helper functions that return promises in a template. The compiled template function would itself return a Q promises of the entire template.
Since this would be used differently than regular templates, it would need to have a separate
compileAsync
function, which would generate template functions that always return promises.Alternatively, the template could specify
@async
to indicate that it should be compiled into a promise-generating function. However, I think that would be a bad idea; the consumer of the template should know in advance what it expects.Since the compiler has no way of knowing which expressions return promises, it would need to compile every expression into a
then()
call; the compiled code would look like this:The text was updated successfully, but these errors were encountered: