The writing of this article takes a long time. It is called xiongwen too much. Be careful and use it slowly
This reason
In fact, after launching RegularJS, I find that searching Regularjs in Google does not give me this picture
Just give me this picture
When I suddenly realized that the name was a university question, I expected that some unsuspecting friends would think it was just a copy of AngularJS. If you are interested in this, you can check out why we built Regularjs.
In this article, I will not straightforward to make direct comparison with presents, but starting from the basic principle of the existing template solutions for a comprehensive classification, at the same time, gives them some or the characteristics of excellent or worse, the basic characteristics of these are essential, namely, it is not level for maintainers and diligent or not limited by, So it’s objective.
What is a template solution?
You can think of it simply as a template engine.
In fact, front-end templating solutions have evolved from “it’s too hard to pick one good Template” to “it’s too hard to pick one good Template out of so many”, template-engine-Chooser! I can’t seem to keep up. Coupled with the rise of DOM-based templating technologies (AngularJS, Knockout, etc.), the field is starting to feel a bit messy and attractive.
This article will provide a comprehensive comparison of three very different templating schemes in the front-end world today, respectively
- String-based template technology (string-based parse and compile processes)
- Dom-based template technology (DOM-based Link or compile process)
- Living Templating hybrid (String based Parse and DOM based Compile process)
The possibilities for the same type of templating technology are the same, that is, dom-based Vuejs can evolve into the same functional hierarchy of AngularJS if they wish.
(Note: This is not a good idea, because another important part of determining such frameworks is their data management layer: whether they are based on dirty checks or setters and getters, for example, is very different.)
It is also important to note that none of these types of templating techniques can be replaced, they can even be used in combination, and will continue to coexist for a long time.
React is also mentioned in this article, and its features are closer to Living Templating.
Before we get into the intro, we need to take a look at InnerHTML, which we have to say is the key element of this article.
innerHTML
I don’t think we need to start with the innerHTML details. We’re so familiar with it, let’s just start with the pros and cons.
InnerHTML is unquestionably good
Before innerHTML became a Web standard, it was already the de facto standard because:
1. It is easy to write and intuitive
Imagine you have to add the following HTML to your document
<h2 title="header">title</h2>
<p>content</p>Copy the code
Use innerHTML directly
node.innerHTML = "<h2 title="header">title</h2><p>content</p>"Copy the code
Use the Dom API in comparison
var header = document.createElement('h2');
var content = document.createElement('p');
h2.setAttribute('title', 'header');
h2.textContent = 'title';
p.textContent = 'content';
node.appendChild(header);
node.appendChild(content);Copy the code
InnerHTML won the contest without a doubt.
Although some frameworks such as MooTools :Element provide efficient apis to help you create DOM structures, innerHTML is probably the best choice for most people
2. It’s fast, especially in Old IE
As browsers evolve, this test can become less realistic, and the gap between innerHTML and Dom Level 1 creating a Dom structure is getting smaller and smaller
3. It completes the String -> Dom conversion
This argument is a bit of a mouthful, and in fact the next two types of template technologies rely heavily on it because of this feature
And yet we are clearly told:
The recommended way to modify The DOM is to use The DOM Level 1 API. — Chapter 15 of “Javascript: The Definitive Guide_”
Why is that?
InnerHTML is sometimes disobedient
1. Security
InnerHTML has security implications. For example:
document.body.innerHTML = "<img src=x onerror='alert(xss)'/>"Copy the code
I know a good programmer like you wouldn’t write code like this, but when HTML fragments aren’t completely under your control (from a remote server, for example), it can be a bomb.
2. It is slow
Wait, you just said it was fast! Yes, but if you replace all the Dom nodes with innerHTML just to replace one attribute, that’s not a wise decision because you know it’s inefficient. So said.
Context is everything
All the talk of performance, function, and sexual function out of context is pseudoscience
3. It is quite stupid
It completely removes all the existing Dom and renders it again, including events and states that no longer exist. As Backbone developers who use innerHTML to render frameworks know, they have to strip views into smaller and smaller pieces to minimize losses. Thus holding the seemingly “perfectly decoupled” architecture system into the abyss of maintenance.
Note: The biggest contribution of React is that it almost provides a smarter innerHTML solution.
4. Unexpected nodes may be created.
Because HTML’s Parser is so “friendly,” it accepts non-standard writing, creating unexpected structures without the developer getting an error message.
We’re starting with the most common “String-based Templating,” and we’re starting with innerHTML on the surface
String-based templating
The string-based template engine’s greatest credit is that it frees you from having to do a lot of string concatenation with logic, and it has some irreplaceable advantages due to its string-based nature.
It is essentially a way to address the need to populate an HTML view with data in a better way than having to write a Big, ugly String concatenation expression. — Cited from www.dehats.com/drupal/?q=n…
The sample
- Mustache and its derivatives: Weak logic
- Dust.js: Strong Logic (recommended)
- DoT. Js: super fast
The basic principle of
As shown in the figure above, we see that the string template strongly relies on innerHTML because its output is a string. Since the focus of this article is not here, we won’t delve further into how they are used.
advantages
- Fast initialization time: Many Angular fans seem to leave this out when they deride String-based templating.
- Isomorphism: Completely DOM-independent, can be used on both the server and browser side (don’t wait to move Phantomjs)
- Better syntax support: Because they are not native DSLS and are based on JavaScript syntax, Parser’s flexibility is not comparable to the DOM-based template technology that is limited to HTML
disadvantages
- Security risks: See
innerHTML
- Performance issues: See
innerHTML
. - Not smart enough: See you
innerHTML
Besides, after render, the data is completely separated from the view.
Although string-based front-end template technologies have gotten faster over the years due to intense competition, most of them are clearly missing some issues
- Guys, you don’t take into account the time it takes to load the output string into the Dom, which is one of the real bottlenecks
- Does it make sense to compare without the same function?
Dom-based Template Engine
In recent years, dom-based templating technology has become popular thanks to Angularjs, but there are some excellent alternatives, such as Vuejs and Avalonjs. See warehouse can discover style also is completely different: 1) a concise grace 2) a bold and unrestrained unruly
The sample
- Angularjs: 28000star need I say more
- Knockout: Knockout is the granddaddy of the Web front-end in this area
A flowchart
Dom-based templatingtechniques don’t actually have a full parse process (expressions aside). If you need to create a view from a string, you must use innerHTML to get the initial Dom structure. The engine then leverages the Dom API(Attributes, getAttribute, firstChild… Etc) to extract instructions, events and other information from the attributes of the original Dom, and then complete the binding of data and View to make it “active”.
So DOM-based templating is more like a process of “linking” and * “rewriting” data to the Dom.
Note that dom-based templating techniques do not necessarily use innerHTML, such as when all templates are written on the entry page, but the parse process is still the browser’s work.
advantages
- Is active: After compile is complete, data and View are still related, that is, you don’t have to rely on manual operation
Dom API
To update the View - Is run-time efficient: local updates can be implemented
- Powerful add-ons like instructions help us develop apps in a declarative way
disadvantages
- See innerHTML for a section
- It doesn’t have a separate Parser, so you have to get the initial node with innerHTML(or the first screen), and its syntax is heavily HTML-dependent, which makes it potentially vulnerable to security issues
- Information is carried in attributes, which are unnecessary and redundant. Parts of the framework read the properties through such methods as
removeAttribute
If you look at the [Angular todomvc] node, you’ll see that its output looks something like this: - FOUC(Flash of unstyled content) : Flash content, needless to say, only the content it first enters the DOM is not the final desired content.
Living Template Engine
Both string-based and DOM-based templating techniques rely more or less on innerHTML, the difference being that the one is mainly about Rendering and the other is about Parsing information
So why not combine the two to completely remove the dependency on innerHTML?
In fact, thankfully, there are already several real-world examples of this.
example
- Htmlbar: A secondary compilation that runs after handlebar
- Ractivejs: independence
- Regularjs is an independent company, one of the authors of this article
The basic principle of
As shown in the figure, the processes for parse and compile are similar to string-based and DOM-based templates, respectively.
Let’s describe both processes in their entirety
1 . Parsing
First we use a built-in DSL to parse the template string and output the AST.
For example, in RegularJS, the following simple template string
<button {{#if ! isLogin}} on-click={{this.login()}} {{/if}}> {{isLogin? 'Login': 'Wellcome'}} </button>'Copy the code
Will be resolved into the following data structure
[
{
"type": "element",
"tag": "button",
"attrs": [
{
"type": "if",
"test": {
"type": "expression",
"body": "(!_d_['isLogin'])",
"constant": false,
"setbody": false
},
"consequent": [
[
{
"type": "attribute",
"name": "on-click",
"value": {
"type": "expression",
"body": "_c_['login']()",
"constant": false,
"setbody": false
}
}
]
],
"alternate": []
}
],
"children": [
{
"type": "expression",
"body": "_d_['isLogin']?'Login':'Wellcome'",
"constant": false,
"setbody": false
}
]
}
]
Copy the code
This process has the following characteristics
- Flexible and powerful syntax, because like string-based templates, DSLS are autonomous, completely independent of HTML. You can imagine the syntax instructions for DOM-based templates. In fact, they don’t even express the logic of that simple template.
- Living template technology requires simultaneous processing
DSL elements
与XML elements
To make the final view layer active, that is, they aredom-awareIn the string templateXML elements
It’s perfectly fine not to care, they’re uniformly regardedText elements
.
2 Compiler
Combined with a specific data model (in RegularJS, a bare data), the template engine hierarchy travels through the AST and generates Dom nodes recursively (without involving innerHTML). At the same time, binders such as instructions, events, and interpolation also bind, resulting in a Dom that is tied to the Model, that is, live.
In fact, the compile process for Living Templates is much purer than dom-based template techniques because it is generated entirely from the AST, rather than rewriting the original Dom.
Take an interpolation of the template code above :{{isLogin? ‘Login’ : ‘Wellcome’}} instead! Once regularJS ‘engine encounters this template and the syntax element node it represents, it enters the following function for processing
// some sourcecode from regularjs
walkers.expression = function(ast){
var node = document.createTextNode("");
this.$watch(ast, function(newval){
dom.text(node, "" + (newval == null? "": String(newval)));
})
return node;
}
Copy the code
As we can see, thanks to the $watch function, text nodes change when expressions are changed, just like AngularJS (regularJS is also based on dirty checking).
Different from DOM-based template technology using Dom nodes to carry information, its intermediate AST carries all the information needed in the Compile process (statements, instructions, attributes… This brings several benefits
- Lightweight, reading and writing in the Dom is inefficient.
- Reusable.
- Serializable, you can preprocess the process locally or on the server side.
- securityBecause security does not need
innerHTML
Help us generate the initial Dom
If you look at the output of Living Template, you’ll see something like this
Only the required content is printed
Living Templating
Living Templating has the advantages of both String-based and DOM-based template technologies
Syntax flexibility is achieved by using a custom DSL such as a string template to describe structures and to carry information after Parse (AST). In the Compile stage, AST and Dom API are used to complete the View assembly. In the assembly process, we can also introduce excellent seeds of DOM-based template technology such as Directive.
Living Template’s cousin — React
React, of course, is a template solution that also subtly circumvents innerHTML, but uses a completely different strategy: React uses a virtual DOM technology that is also based on dirty checking, but differs in that its dirty checking takes place at the View level, in the Virtual DOM, allowing local updates to be implemented with minimal overhead.
Example
var MyComponent = React.createClass({ render: function() { if (this.props.first) { return <div className="first"><span>A Span</span></div>; } else { return <div className="second"><p>A Paragraph</p></div>; }}});Copy the code
The same logic is described using regularJS
{{#if first}}
<div className="first"><span>A Span</span></div>
{{#else}}
<div className="second"><p>A Paragraph</p></div>;
{{/if}}
Copy the code
It’s a matter of opinion, but I prefer to use templates to describe structures rather than mixing Virtual DOM and JS statements. How about you?
It is worth mentioning that React has a lot of PLACEHOLDER ID due to its feature that internal node substitutations between render and React are unpredictable (see here), so it cannot retain information effectively. You can also see the nodes generated by React-Todomvc
A comprehensive comparison table
Contrast /Solutions | String-based templating | Dom-based templating | Living templating |
---|---|---|---|
example | Mustache,Dustjs | Angularjs, Vuejs | Regularjs, Ractivejs, HTMLbars |
Grammatical flexibility | ♦ ♦ ♦ | ♦ | ♦ ♦ |
active | X | ♦ ♦ ♦ | ♦ ♦ ♦ |
performance | Original: ♦ ♦ ♦ Update: ♦ |
Original: ♦ Update: ♦ ♦ ♦ |
Original: ♦ Update: ♦ ♦ ♦ |
security | ♦ | ♦ ♦ | ♦ ♦ ♦ ♦ ♦ |
The Dom has nothing to do | ♦ ♦ ♦ ♦ ♦ | X | ♦ ♦ |
SVG support(*1) | X | ♦ ♦ | ♦ ♦ ♦ |
2. They are not impossible to exist together. For example, you can use string templates to generate template strings for dom-based templates.
The resources
- Template Engines by @Sendhil
- string-templating-considered-harmful