Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Cutting-edge web development with jsRazor: tiny JavaScript that replaces ASP.NET (PHP, MVC, JSP, etc.) rendering!

5.00/5 (16 votes)
3 Jun 2013CPOL21 min read 73.1K   460  
jsRazor is unbeatably powerful and stupidly simple client-side rendering approach that consists of ONLY TWO functions. Tiny javascript library entirely eliminates the need for server-page rendering, in the same time giving your apps unmatched simplicity and flexibility.

Overview

Being a back-end programming expert, I was always leaning towards the server-side template based rendering. However, a while ago, after working with numerous client-side templating engines and weighing all pros and cons, I finally decided to switch most of my web apps to the pure JavaScript driven templated UI. While there are tons of existing frameworks for this, and some of them work really well, there are several reasons that pushed me to roll out my own client-side template rendering solution. Working with other frameworks I always had a feeling that there was an easier solution. DOM based libraries flood your HTML templates with dummy elements and attributes, making it hard to read, plus performance suffers from heavy DOM transformations. Client-side MVCs and compiled templates are very interesting, but say goodbye to clear WYSIWYG markup. Plus the framework with the compiler themselves are huge, plus the need of  extra frameworks for debugging all this, plus long learning period. In my opinion, this all is much more over complicated than it should be. And likely this complexity is visible to all those devs who hesitate to use client-side rendering and prefer to stick with MVC4 Razor, PHP, and others.

I always say "simple must stay simple" (slogan on my dev site), and I'm writing this post to share my own client templating solution that I came up with after using other frameworks. On one hand, this new solution allows to render the output of unlimited complexity. On the other hand, it is stupidly and unbeatably simple. It's simpler than you can imagine. The whole library is about 100 lines of code, it's super efficient, it consists of two functional primitives, and you literally have to spend 2 minutes to learn it.

Oh yes, I know how this sounds Smile | :) The other part of me had the same reaction when my dark side came up with this rendering solution. So, let me guide you through the approach, do some good examples, and demonstrate how it all works.    

Note: This article is also published on my site here. If you wish, you can leave you comments and download all source code from there. Project repo is on the GitHub: http://github.com/rgubarenko/jsrazor 

UPD: I've made important changes to jsRazor to turn it into the ultimate client-side application framework. I'm going to publish an overview article as well as jsRazor vs. AngularJS article towards the end of May. See my comment for more details. 

UPD2:   jsRazor vs. AngularJS: "Todo" and "JS Projects" demos with jsRazor! article has just been published! The article does to actual side to side comparison of jsRazor and AngularJS using demo apps.


Table of Contents 

Introduction

The idea of generating HTML output by executing JavaScript against JSON and client-side template is not new. For at least 5 years it was a continuous discussion whether back-end application task should be reduced to providing JSON data only, leaving rendering task for the client-side. After pushState() feature of HTML5 came out, many devs started leaning towards the client-side more and more.

I started working with client-side from using JSONDataSet from Adobe Spry framework. It's a DOM based library that works pretty well for certain tasks, but it's not capable of doing fully custom output. Then I used JavaScriptMVC, Knockout, Angular, and some others from this list here. I liked MVC and compiled JS templates for flexibility and customization. I suggest you take a look at the frameworks I listed in order to feel how the solution below is different from them. However, there are reasonable opinions that if, for example, client-side MVC syntax does not make it much simpler in terms of programming, why not just use server-side MVC4 or PHP5 to achieve the same? Moreover, server-side debugging is a way more convenient. Yes, client frameworks can do a lot, but why bother switching from our lovely sever-side, unless there is some glaring programming benefit?

In this short article I'll show that there is actually a huge benefit and many good reasons to switch. I'll propose the solution that DOES make programming simpler and more flexible. It makes it almost trivial actually, so every graphics designer with knowledge of JavaScript can do page rendering like senior expert. This raises another interesting question - if the entire complex server-side rendering mechanism can be replaced with trivial JavaScript, do we need server page frameworks (ASP, MVC, PHP, whatever) at all? Sounds scary, huh?

OK, let me now introduce my simple solution to client-side template rendering. 

Solution 

Assume we have some JSON data on the web page. There are several good options to load JSON, but the best practice is to include JSON data within the page on initial page load (i.e. no extra Ajax call needed) and then use async Ajax to update parts of JSON data on demand. But this is offtopic here, so we just assume that JSON is already available.

Now, what's the best way to build HTML based on this JSON? After thinking about this with a pen and a paper, I came to the conclusion that, speaking abstractly, every possible rendering task can be accomplished as a random combination of two functional primitives

  • repeat - repeats fragment of HTML code for each object in array
  • toggle - shows or hides fragment of HTML depending on boolean flag
I call this solution jsRazor, because it shaves off all redundant complexity. Any crazy UI design that you ever come up with, you can achieve by combining only two functionals in different nesting configurations.

Templates

The key part of our solution is the template and the way jsRazor works with it. Same principle "simple must stay simple" is applied here: jsRazor does not do DOM transformations, JS compilation, or anything like this. The template is entirely treated as plain text and all transformations are simple search-replace-insert operations over the string object. There is nothing in JS world that could be more efficient than this!

Typical jsRazor template looks like the following:

HTML
some HTML
<!--repeatfrom:name1-->
  HTML fragment to repeat 
  plus value placeholders {Value1}   
  <!--repeatfrom:name2-->
    nested HTML fragment to repeat 
    plus value placeholders {Value2}
  <!--repeatstop:name2-->
  more HTML
  <!--showfrom:name3-->
    HTML fragment to show or hide
  <!--showstop:name3-->
  more HTML here
<!--repeatstop:name1-->
more HTML here

So, everything is very simple here. To mark target fragment for repeat function we use <!--repeatfrom:name--> and <!--repeatstop:name--> comment limiters. For toggle function, use <!--showfrom:name--> and <!--showstop:name--> limiters. To output actual values, use placeholders of {SomeValue} format. Now, combine these two simple functionals in any possible configuration and get the desired output. For example, to achieve logical OR on toggle, you put two or more toggles beside each other; for logical AND, you nest one toggle into another. And so on.

The good thing about comments is that they don't interfere with your HTML and do not break WYSIWYG experience. Comment limiters are used by default, but you can change them to any format you like (see next section). Sometimes you want do deliver your template wrapped inside a comment itself, so that setup scripts do not touch the template. In this case you'd need to change limiter format to something other than comment.

Now let's see the actual functions that do all work. 

Functions  

As I stated before, jsRazor consits of only two functions to accomplish all work. I decided to create them as jQuery plugin in jsrazor namespace. This is just because I like jQuery plugin syntax, but there is no actual framework dependency. Although I’ll use jQuery in my examples, the plugin will work fine without jQuery library. Let’s see the actual call syntax and parameters.

First, there is one setting that you can use to change limiter format. To use [repeatfrom:name] format instead of comments, you'd have to do the following:

JavaScript
$.jsrazor.settings.limiterFormat = "[{type}:{name}]";

And now let's look at the functions. First one is repeat:

JavaScript
$.jzrazor.repeat(template, name, items[, render])  
DescriptionRepeats the fragment surrounded by limiters inside the template
ReturnsThe resulted rendered content
Parameters
  • template (Type: string): Plain text template that contains fragment to repeat.
  • name (Type: string): Name token that identifies fragment limiters e.g. <!--repeatfrom:name--> and <!--repeatstop:name-->
  • items (Type: Array): The array of objects of any type that repeater will iterate through.
  • render (Type: Function(string tmp, Number idx, Object item)): Optional rendering callback invoked on every iteration to return rendered content for current item. Parameter tmp contains the template for current item. Parameter idx is the position of item in the items array passed to the original function call. If current item is JSON object, then values of its properties of string or Number type are output to {<property-name>} placeholders. If current item is of string or Number type, then its value is output to {item} placeholder. Note that automatic output of properties into placeholders is done by plugin AFTER the rendering callback returns.

In other words, inside render callback you process content passed in tmp and return the desired output for the current item. All item properties are output to {<property-name>} placeholders automatically. To insert custom values, I suggest usage of placeholders in {SomeValue} format replaced with string.replace(..) function, but you can choose any format at your own preference. There is no limitation on processing inside the callback, so you can achieve any custom output you like.

Second function is toggle: 

JavaScript
$.jzrazor.toggle(template, name, flag)   
DescriptionShows or hides the fragment surrounded by limiters inside the template
ReturnsThe resulted rendered content
Parameters
  • template (Type: string): Plain text template that contains fragment to toggle.
  • name (Type: string): Name token that identifies fragment limiters e.g. <!--showfrom:name--> and <!--showstop:name-->
  • flag (Type: Boolean): Should be true to show fragment, and false to hide it.

Everything is trivial here. If flag is true, then fragment stays (limiters are removed). Otherwise, both fragment and limiters are removed. 

Now let's just think for a moment. Two JavaScript functions instead of the entire ASP.NET, PHP, JSP, etc. rendering mechanism! All those server controls, control flow statements, binding expressions, page lifecycle, etc. etc. suddenly just become redundant. In terms of 3-tier web app design, the entire presentation goes away to the client-side. Server-side is left with data layer and the business logic, and only needs to generate JSON data feeds. 

Sounds good, doesn't it? Now it's time to see this all in action!

Examples 

I’ll use same JSON data as Adobe Spry uses for their demos - I hope they don’t mind Smile | :) So, assume that JSON is created on the back-end from our data layer and is delivered to the client-side. Here are some good examples. 

Example 1  

Assume we have an array of simple JSON objects describing  colors:

JavaScript
var data_Colors =
[
  {
    color: "red",
    value: "#f00"
  },
  {
    color: "green",
    value: "#0f0"
  },
  // ...
];

We want to output the colors as comma separated names followed by hex values in brackets. Here is the desired output:

ex1

I do identical output twice just to demonstrate slightly different JavaScript syntax:

HTML
<div class="cont-ex1">
  <div>
    1) <!--repeatfrom:colors1-->{color} ({value}), <!--repeatstop:colors1-->
  </div>
  <div>
    2) <!--repeatfrom:colors2-->{color} ({value}), <!--repeatstop:colors2-->
  </div>
</div>

There are 2 repeaters here beside each other: colors1 and colors2. They both will do the same, but with little different code just demonstrate one feature to you. Now let's see the actual JavaScript:

JavaScript
1: var $cont = $(".cont-ex1");
2: {
3:   var output = $cont.html();
4:   output = $.mksft.repeat(output, "colors1", data_Colors); // most basic default repeater
5:   output = $.mksft.repeat(output, "colors2", data_Colors, function (tmp, idx, item) { return tmp; });
6:   $cont.html(output);
7: }

All we do here, we get the template from inner HTML of some element, process it, and insert the result back. I use jQuery to work with inner HTML, but, as I mentioned earlier, plugin itself does not depend on any framework. 

In our case, template is taken from inner HTML of <div class="cont-ex1"> container and assigned to output variable. First, we apply colors1 repeater to it on line 4. Notice that optional render callback is omitted, so there is no custom processing, but only automatic placeholder replacement based on JSON object properties. In the template we used {color} and {value} placeholders which will be replaced with color and value properties of current item on each iteration.

On line 5 we apply second colors2 repeater. The only difference is that I included render callback this time. All this callback does, just returns the current item template without modifications, which is essentially the same as omitting the callback for colors1 repeater.

Example 2  

One more basic example. Assume we have an array of values:

JavaScript
var data_Numbers = [100, 500, 300, 200, 400];

We want to output them as following:

ex2

Template is simple:

HTML
<div class="cont-ex2">
  <div><!--repeatfrom:numbers-->{item}, <!--repeatstop:numbers--></div>
</div> 

The JavaScript code is even simpler:

JavaScript
var $cont = $(".cont-ex2");
{
  var output = $.mksft.repeat($cont.html(), "numbers", data_Numbers);
  $cont.html(output);
}

No need for render callback here. Recall from API, when current item is of string or Number type, then its value automatically output into {item} placeholder. Done.

Example 3 

In this example let's do some custom processing. Our data is the same array again, but this time, for each number N in the array we want to output N-1<N<N+1. Here is the desired output:

ex3

For N-1 and N+1 values we will need custom placeholders. We don't want trailing comma after the last item as it was in our previous examples. To accomplish this, we will need to use the fragment toggle. Here is the template:

HTML
<div class="cont-ex3">
  <div>
    <!--repeatfrom:numbers-->
    {ItemL}&lt;{item}&lt;{ItemM}<!--showfrom:not-last-->, <!--showstop:not-last-->
    <!--repeatstop:numbers-->
  </div>
</div>

In this template we have {ItemL} and {ItemM} extra placeholders. Also, comma is wrapped into the not-last toggle and will be displayed only when current item is not last one in the array. Now let's see the code:

JavaScript
1: var $cont = $(".cont-ex3");
2: {
3:   var output = $.mksft.repeat($cont.html(), "numbers", data_Numbers, function (tmp, idx, item)
4:   {
5:     // toggle conditional area
6:     tmp = $.mksft.toggle(tmp, "not-last", idx < data_Numbers.length - 1);
7:     // custom placeholders
8:     tmp = tmp
9:       .replace(/{ItemL}/g, (item - 1))
10:       .replace(/{ItemM}/g, (item + 1));
11: 
12:     return tmp;
13:   });
14: 
15:   $cont.html(output);
16: }

OK, now it's more interesting, because render callback has some processing in it! On line 3 we apply numbers repeater as before. Then, render callback needs to return rendered result for every item. On line 6 we apply not-last toggle to the fragment with comma. Recall that 3rd parameter is flag that needs to be true to show the fragment, so in our case it is true when item is not last one in the array. Then, on lines 8-10 we output our custom placeholders by simple string.replace(..) operation. Value of item equals current item in the input array i.e. in our case it an integer number.  That's all.

Example 4   

And the last example for today is the complex JSON with multiple nested arrays that require nested repeaters to output them. We will need to combine them with several fragment toggles to achieve even more custom output. Here is a JSON describing donuts menu:

JavaScript
var data_Donuts =
{
  "donuts":
    [
      {
        "id": "0001",
        "type": "donut",
        "name": "Cake",
        "ppu": 0.55,
        "batters":
          [
            { "id": "1001", "type": "Regular" },
            { "id": "1002", "type": "Chocolate" },
            { "id": "1003", "type": "Blueberry" },
            { "id": "1004", "type": "Devil's Food" }
          ],
        "toppings":
          [
            { "id": "5001", "type": "None" },
            { "id": "5002", "type": "Glazed" },
            { "id": "5005", "type": "Sugar" },
            { "id": "5007", "type": "Powdered Sugar" },
            { "id": "5006", "type": "Chocolate with Sprinkles" },
            { "id": "5003", "type": "Chocolate" },
            { "id": "5004", "type": "Maple" }
          ]
      },
      // ...
      {
        "id": "0004",
        "type": "bar",
        "name": "Bar",
        "ppu": 0.75,
        "batters":
          [
            { "id": "1001", "type": "Regular" }
          ],
        "toppings":
          [
            { "id": "5003", "type": "Chocolate" },
            { "id": "5004", "type": "Maple" }
          ],
        "fillings":
          [
            { "id": "7001", "name": "None", "addcost": 0 },
            { "id": "7002", "name": "Custard", "addcost": 0.25 },
            { "id": "7003", "name": "Whipped Cream", "addcost": 0.25 }
          ]
      },
      // ...
    ]
};

Here is the output we want to achieve:

ex4

 Here is a template to achieve this:

HTML
1: <div class="cont-ex4">
2:   <ul>
3:     <!--repeatfrom:donuts-->
4:     <li>[{id}] | {type} | <b>{name}</b> | ${ppu} 
5:       <ul>
6:         <li>Batters
7:           <ul>
8:             <!--repeatfrom:batters-->
9:             <li>[{id}] {type}</li>
10:             <!--repeatstop:batters-->
11:           </ul>
12:         </li>
13:         <li>Toppings
14:           <!--showfrom:has-chocolate-->
15:           <span style="color:brown;">
16:              {CountChocolate} chocolate toppings available
17:           </span>
18:           <!--showstop:has-chocolate-->
19:           <ul>
20:             <!--repeatfrom:toppings-->
21:             <li>[{id}] {type}</li>
22:             <!--repeatstop:toppings-->
23:           </ul>
24:         </li>
25:         <!--showfrom:has-fillings-->
26:         <li>Fillings
27:           <ul>
28:             <!--repeatfrom:fillings-->
29:             <li>[{id}] {name}
30:               <!--showfrom:cost-extra-->
31:               <span style="color:red;font-weight:bold;">+${addcost} = ${NewPPU}</span>
32:               <!--showstop:cost-extra-->
33:             </li>
34:             <!--repeatstop:fillings-->
35:           </ul>
36:         </li>
37:         <!--showstop:has-fillings-->
38:       </ul>
39:     </li>
40:     <!--repeatstop:donuts-->
41:   </ul>
42: </div>

So, to output our hierarchical data we want to use nested HTML lists. First level outputs donuts and their direct attributes using donuts repeater on lines 3-40. Second level outputs batters (lines 8-10), toppings (lines 20-22), and fillings (lines 28-34) arrays. Some donuts do not have fillings, and in this case we want to show nothing instead of showing "Fillings" title with empty list. To achieve this, we enclose the entire fillings section in the has-fillings toggle on lines 25-37. Next, some fillings add extra cost to PPU. When this is the case, we want to output extra amount in red font using "+$X=$X1" format where X is extra cost and X1 is the updated PPU. For this purpose we have cost-extra toggle on lines 30-32 and custom {NewPPU} placeholder. Finally, if there are any chocolate toppings available, we want to show a message like "2 chocolate toppings available". For this purpose we have another has-chocolate toggle on lines 14-18 and {CountChocolate} placeholder. And this is all for the template! Now let's see the code:

JavaScript
1: var $cont = $(".cont-ex4");
2: {
3:   // first level repeater for all donuts
4:   var output = $.mksft.repeat($cont.html(), "donuts", data_Donuts.donuts, function (tmp, idx, item)
5:   {
6:     // default repeaters for batters and toppings
7:     tmp = $.mksft.repeat(tmp, "batters", item.batters);
8:     tmp = $.mksft.repeat(tmp, "toppings", item.toppings);
9: 
10:     // display fillings only if there any
11:     tmp = $.mksft.toggle(tmp, "has-fillings", !!item.fillings);
12:     // render fillings list
13:     if (item.fillings)
14:     {
15:       var ppu = item.ppu; // save ppu for child value scope
16:       // custome repeater for fillings to display extra cost and new PPU
17:       tmp = $.mksft.repeat(tmp, "fillings", item.fillings, function (tmp, idx, item)
18:       {
19:         // display price warning if there is additional cost involved
20:         tmp = $.mksft.toggle(tmp, "cost-extra", item.addcost > 0);
21:         // custom placeholder to display new PPU value
22:         tmp = tmp.replace(/{NewPPU}/g, ppu + item.addcost);
23:         return tmp;
24:       });
25:     }
26: 
27:     // display number of chocolate toppings
28:     var countChoco = 0; // count number of chocolate toppings
29:     $.each(item.toppings, function (idx, item) { if (/chocolate/i.test(item.type)) countChoco++; });
30:     tmp = $.mksft.toggle(tmp, "has-chocolate", countChoco > 0); // show/hide chocolate message
31:     tmp = tmp.replace(/{CountChocolate}/g, countChoco); // render chocolate topping counter
32: 
33:     return tmp;
34:   });
35: 
36:   $cont.html(output);
37: }

Note that due to JavaScript variable scoping, I can re-use tmp, idx, and item variables in all nested repeater render callbacks, which saves a lot of code lines. 

So, outer donuts repeater we have on line 4. Render callback starts from applying nested batters and toppings repeaters on lines 7-8. We leave them default, since we only need to output property placeholders. Next, on line 11 we apply our has-fillings toggle to hide the entire fillings area if there are no fillings. And if there are fillings, we output them applying fillings repeater on line 17.  On line 15 I have to save PPU value into separate ppu variable, because item will have different meaning in the render callback or the nested repeater. Inside render callback for fillings repeater I start from applying cost-extra toggle on line 20. Then on line 22 I output value for {NewPPU} placeholder. Finally, we need to deal with chocolate toppings. We count them on lines 28-29, apply has-chocolate toggle on line 30, and output count on line 31. We're DONE! 

I think you got the idea. Combining two simple functions you can achieve output of any complexity based on JSON of any structure - that's all. The template is as simple and transparent as it can be. Comment limiters do not interfere with HTML leaving your template markup absolutely clean and viewable in any HTML editor. I don't see any reason to use compiled templates when you can achieve here all output you need in a stupidly simple way.

Now it's time to summarize everything we've seen so far.

Client-Side Solution Summary

I'll not go deeply into general pros and cons of client-side rendering, because it was spoken already thousand times. Instead, I'll mostly focus on the aspects specific to jsRazor solution.

Learning period 

Seriously, how long did it take to read Solution and Examples sections above? 5 minutes? 10? And that's all you need to know about jsRazor. There is no learning required here, while other client-side rendering frameworks might get quite complex. For example, JS MVC requires quite a bit of learning plus extra framework to debug you views. I'm not even mentioning server-side like ASP.NET here, where it takes several years to become rendering expert and learn all peculiarities of the server controls. Here, after 10 minute tutorial literally every HTML designer becomes able to build apps with flexibility that no server-side framework can achieve!

Development process 

Look at our last example. Having that JSON data, it would take you 10 minutes to create the template and 5 minutes to write the JavaScript, agreed? It's trivial and transparent. Just for comparison, how long would it take you to do the same in ASP.NET, MVC, JSP? You'd probably use some monster like DataGrid?  MVC Razor would take less than classic ASP.NET, but still much more than jsRazor. Now, what about client-side? Compiled templates and JS MVC would do the job, but syntax and simplicity would not be even close to jzRazor solution. Here is the list of client MVCs that you can take a look for comparison.

Developer skill level 

Due to overall simplicity, jsRazor rendering task can be accomplished by HTML designer with basic knowledge of JavaScript. Furthermore, to maintain the already existing solution even lower skill will fit. The back-end developer gets involved only when there is need to create new JSON feeds or modify existing ones, which also does not require much framework knowledge. On the other hand, creating a regular server-page site requires senior programmer from the beginning, and at least a medium level programmer to maintain the existing solution. The client-side MVC also requires advanced developer, especially for debugging the code.

Architecture

Application architecture is where jsRazor wins everywhere! First of all, if back-end is used only for generating JSON, this automatically means 100% presentation separation. Second, jsRazor also provides separation on the client-side! Look, in compiled templates you have your code mixed with HTML markup everywhere. Then compiler turns it into executable JavaScript. In jsRazor template is separate and code is separate just by design. Absolutely separate. So it's double separation here: back-end separation plus front-end template/controller separation.

It was also noted many times by other IT experts that client-side rendering provides the maximum theoretical level of client-sever app simplicity. With trivial jsRazor templates this feature becomes even more obvious. No matter how complex your UI functionality is, on the back-end it's always a bunch of JSON endpoints, and on the front-end it's always a bunch of simple templates with tiny JavaScript controller (if I can call it this way).

What about performance?

Number one concern that comes to our mind about client-side rendering is performance. There are usually 2 arguments that I hear against client-side rendering in general: need for JSON data call on initial page load, and need for executing a bunch of JavaScript before page is displayed.

Regarding Ajax call on the initial load, I already mentioned that it is not really needed if application is written properly. Initial JSON has to be inserted into the page and loaded together with it, so it's available without any additional calls, and Ajax should be used to update existing JSON or load extra data. So there is no problem here. It's just a design consideration that every developer have to keep in mind.

Next question is how bad is it to execute JS to finalize page UI? Well, I would say that today, when tiny smartphones are capable of doing FullHD playback, this concern becomes negligible. Just to understand what we're talking about here, let's see the use case. I'll use ASP.NET here as example, but results are true for other frameworks too, because, in terms of workflow, they all are pretty much the same.

Page rendering consists of a number of steps. Let's depict the steps in the period between client request hitting the page and the page is displayed in the user browser. The picture is below:

page-rendering-steps-1

There are more steps in a real world, but this is just a model. So, request passes through IIS and gets to ASP.NET. Then there is some housekeeping to run modules, setup context, etc. Then page begins lifecycle execution: usually we get entities from data layer and process them through some business logic. Then page is rendered (time spent is tR). Then housekeeping again, and then response is sent back to client through the network (time spent is tW). After it reaches the client, it's displayed in the browser. If jsRazor rendering is used (time spent is tR*), then it has to execute before the page is displayed. Let's call "case A" the case where pure server-side rendering is used, and "case B" - where jsRazor client-side rendering is used instead.

In case A, there is only tR. In case B - only tR*, because tR entirely goes away. So, roughly, it comes to comparing tR and tR*, right? I did not do any actual benchmarking here, so let's just think theoretically. To render the server-page (the tR), ASP.NET builds control tree, goes through it, calls entire lifecycle for each control, etc. - a lot of work. However, this is all compiled code on the server, so, unless the page is really crazy complex, the rendering should be fast. On the other hand, tR* is taken by browser JavaScript. The entire rendering procedure of jsRazor is based on simple string operations, so it should be a way more efficient. However, it runs in the browser and JavaScript is slower than compiled code. So, intuitively I think that tR<tR*, but I'll try to do actual benchmarking in the future. Anyway, even if this is the case, this is still NOT a concern, because it's not going to be visible to the eye anyway.

If we think further, we may notice that tW for case B is actually less than tW for case A. This is because in case B, the response is a raw page with templates and JSON, but in case A, it is a completely rendered web page which is much larger. And the bigger your data grid is, the bigger will be the difference between tW in both cases. So, jsRazor approach gives much better performance in this terms. For slow internet connections this could be a big win actually.

Also, there is a benefit for server load, since we just take a large part of processing off the server. We can go further and say that there is no need to use ASP.NET for generating JSON and use web services instead. This would take even more load off the ASP.NET.

Caching is something where server-side rendering will be faster. Whether it is ASP.NET page cache or network level cache (CDN), for case B we only can cache the raw pages and JSON data, which means that tR* is always involved. In case A we cache fully complete pages that do not need any processing. So, under these conditions, case A will be tR* faster than case B. This is something to mention, but NOT a big deal at all. Again, in case of trivial JavaScript string operations that jsRazor does, tR* is negligible.

Conclusion

Of course, there are certain types of applications that may require server-side rendering only. Paradigm shift is always hard to accept, but for regular Web 2.0 apps (e-commerce, portals, social apps,  etc.) it seems like pure client-side rendering in general and particularly jsRazor is a much simpler and more flexible solution. A huge part of server-page framework can be replaced with two tiny JavaScript functions - is not it cool?

Also consider another important side of this. A part of work that was usually done by back-end developers, can now be done by HTML designers! This is actually very good, because it means more division of labour within the development team, and more spare time for busy senior dev team members Smile | :)

Visit jsRazor page for download links and more info. Visit GitHub repo if you wish to contribute: http://github.com/rgubarenko/jsrazor

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)