Skip to content

Instantly share code, notes, and snippets.

@creationix
Created December 5, 2011 19:12
Show Gist options
  • Save creationix/1434837 to your computer and use it in GitHub Desktop.
Save creationix/1434837 to your computer and use it in GitHub Desktop.
Sanity check for async template idea
Creationix.route("GET", "/", function (req, res, params, next) {
render("frontindex", {
title: query("index", "title"),
links: query("index", "links"),
articles: loadArticles
}, function (err, html) {
if (err) return next(err);
res.writeHead(200, {
"Content-Length": Buffer.byteLength(html),
"Content-Type": "text/html; charset=utf-8"
});
res.end(html);
});
}),
<!doctype html>
<html>
<head>
<title>@title()</title>
<link rel="stylesheet" href="style.css"/>
</head>
<body>
@render("topbar", this)
<div class="container_16">
<div class="grid_11">
<div class="section">@render("summary", articles)</div>
</div>
<div class="grid_5">
<div class="section">Sidebar</div>
</div>
</div>
@render("footer", this)
</body>
</html>
@FugueNation
Copy link

Our framework has solid modeling, with validation and all so our controllers consist of rather thin logic. But there data dependencies are a bit more hierarchic, so we can't really run all our queries in parallel, for example first we need to grab the account info, and based on that grab stuff from other places.
Meaning our typical controller involves about 2-to-3 stages of async processing before we can actually render the final template. With the sample above assumes a single depth of data, which means that it looks really clean, so in our case the final parallel data collection phase would be simplified, that is helpful, but because of the other few layers of control we can't eliminate it all with just Corn. Not that I'm asking for Corn to be a do-it-all library, it already plays nice with the typical callback scheme, so it's just a matter of integration, between controller/view as unless you have a very simple system where the controller kind of disappears like it does in your examples above

On a side note I'm not really sure how query works without a callback, do you wrap the query tuple again with "[render]this" behind the scenes? Or is it some other kind of cool trick?

@creationix
Copy link
Author

I realise that I didn't show enough code in this example. The full query for loadArticles can be found at https://github.com/c9/nog/blob/master/server.js#L53-85.

query() is just a simple helper that does a db query and returns the result in a callback. If you don't provide a callback in the first call, it returns a curried version of itself. https://github.com/c9/nog/blob/master/server.js#L100-104

Load Articles does several manual db joins to gather the data. It is hand written async code and runs as much parallel as possible, but clearly I can't load the author's file without first loading the article's metadata to know who the author is.

So I think there are two kinds of async logic in rendering a view. The first is to know what page to render. This is decision logic and shouldn't be embedded in a view. Usually the url tells enough that we know right away what to load, but this might not always be the case. The second kind of logic is, once we know what to do, we need to gather and load all the required data.

This is the part I propose the view handle for us. For complicated things like "loading a listing of article ids and then loading those articles in parallel and loading the author data for each article as the author name is known" I still think hand-written code is fine. Nested async code is quite nice and efficient in small amounts.

Caching, batching, and request pooling can integrate very nicely with this model and should be for anything that involved real resources like file descriptors or 500 concurrent requests for the same page will crash your server.

Thanks everyone for the input! Keep it coming.

@polotek
Copy link

polotek commented Dec 7, 2011

Here's another gist with some really crazy ideas :) https://gist.github.com/1439922

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment