Both the backend Java, PHP, and the front-end JavaScript are constantly evolving, and their ultimate purpose is to improve the development efficiency of RD.

Take Java as an example, from the beginning of Javaweb servelet + Tomcat, evolution to SpringMVC, and then evolution of SpringBoot, gradually removed all kinds of beans as configuration items, the previous complex XML writing method is all wrapped through annotations. The overall package of Tomcat, research and development efficiency was geometrically improved. After that, it gradually evolved into SpringCloud, which integrates numerous micro-service frameworks and meets the rapid iteration and rapid modular development of background requirements in the group.

JavaScript, like Java, has evolved into thousands of frameworks over the past decade. And because of the openness of its design, it is very easy to compile and escape, so that it can play a role in all aspects. For example, JavaScript can be used to write iOS and Android apps, and can also be used to write desktop clients. Node.js with JavaScript can also support I/O intensive applications very well, and plays an important role in taobao Double eleven first class scene. We can even use it to train AI models, edit videos/images, write 3D games, etc.

So from the perspective of business development of ordinary enterprises, why is it necessary to upgrade the JavaScript framework from the old native JS writing method to the current popular vue.js or React?

Most front-end developers will tell you that upgrades are easy to maintain, make development more efficient, and get rid of historical baggage. But as a team leader, or a back-end engineer, I’m sure you may never understand what he’s saying, or what he’s saying is not supported by facts. I’ll explain why it’s important to upgrade from the history of JavaScript to the two most common page requirements on the front end.

The history of JavaScript

The birth of JavaScript

In 1994, Netscape released version 0.9 of its Navigator browser. This version of the browser is only for browsing and does not have the ability to interact with visitors. Netscape desperately needed a web scripting language that would allow browsers to interact with the web.

What is a Web scripting language? Netscape had two options: one was to take existing languages like Perl, Python, Tcl, Scheme, and so on, and allow them to be embedded directly into web pages; The other is inventing a whole new language.

Both options have their pros and cons. The first option is easier to promote by taking advantage of existing code and programmer resources. The second option, which favors a fully applicable language, is easier to implement.

Netscape’s management struggled to make up its mind about which option to pursue.

That’s when another big thing happened: Sun introduced the Oak language to the market in 1995, renamed Java.

With Sun’s hype that it could “Write Once, Run Anywhere,” it seemed likely to dominate the future.

Netscape was moved and decided to form an alliance with Sun. Not only does it allow Java programs to run directly in the browser as applets; I even considered embedding Java directly into web pages as a scripting language, only to abandon it later because it would have made HTML pages too complex.

Anyway, the situation was that the entire management of Netscape was Java believers, and Sun was completely involved in the web scripting language decisions. As a result, Javascript was later brought to market by netscape and Sun, and it was no accident that the language was named “Java + Script”.

Why is JavaScript a design flaw

There are three objective reasons why Javascript design isn’t perfect.

The design phase was too hasty

JavaScript was designed in ten days. Moreover, designers are there to deliver to the company.

The language, on the other hand, was designed to handle simple web interactions (such as checking “username”) without considering the needs of complex applications. Designers never dreamed that JavaScript would be able to create web pages as large and complex as Gmail.

Without precedent

JavaScript combines both functional and object-oriented programming, possibly for the first time in history. And to this day, JavaScript remains the only major language in the world that uses the Prototype inheritance model. This leaves it with no design precedent to follow.

Premature standardization

JavaScript moves so fast that there is no time to tweak the design.

May 1995: Design plan finalized; October: Interpreter developed successfully; December: Launched to the market, it was immediately widely accepted and used in large numbers by users worldwide.

JavaScript lacks a process of growing from small to large, slowly accumulating users, but rather a continuous, explosive proliferation of growth. The large number of established web pages and amateur web designers make it difficult to adjust the language specification.

To make matters worse, the JavaScript specification has not yet been adjusted and solidified.

In August 1996, Microsoft intervened strongly and announced the launch of its own scripting language Jscript. In November netscape decided to apply for an international standard for JavaScript in order to thwart Microsoft. In June 1997, the first international standard ecMA-262 was formally promulgated.

In other words, a year and a half after JavaScript came out, there was an international standard. Design flaws were standard before they were fully exposed. C, by contrast, came nearly 20 years before an international standard was issued.

And over the next decade, companies have launched their own browsers, as well as for their own browser features, the implementation of different browsers are uneven, written in different ways, which makes front-end programmers spend a lot of time dealing with the compatibility issues of each browser.

The birth of the jQuery

JQuery’s official website is very accurate about its introduction:

jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript.

JQuery is a fast, small, and feature rich JavaScript library. It works perfectly across multiple browsers using easy-to-use apis, making THINGS like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler. JQuery is versatile and extensible. It changed the way millions of people write JavaScript.

As we mentioned earlier, each browser has its own JavaScript implementation that is inconsistent with each other. For example, some browsers support Array forEach traversal, while others do not. Some browsers can select a page element through the style picker, while others do not. When jQuery came along, it wiped out the capabilities of all the major browsers in the world.

As long as the front-end programmer introduces a jQuery page and writes the code as jQuery does, it will run perfectly in all browsers.

That’s not all jQuery offers. It also provides three core tools: DOM batch traversal and manipulation, event handling, and Ajax. Its chained calls also pioneered the convenient chained writing of JavaScript.

Dom batch traversal and manipulation

One of the most important capabilities of jQuery beyond smoothing out browser implementations is the page Element (Dom) selector, which allows you to select elements (Dom) within a page by element style, ID, content, etc.

For example: Get all

Using native JavaScript:

  1. You need to get all of the pages first<button>The element
  2. Iterate to see if the element contains'continue'style
  3. Iterate and change the contents to next… .

Regardless of whether this is a hassle or not, the different compatibility between browsers for element selectors, traversal, and modification is nasty enough.

Using jQuery:

$("button.continue").html( "Next Step..." );
Copy the code

The event processing

JQuery smoothes out the differences between browsers in how they listen for events like click and incorporates the power of Dom batch selectors.

For example, when clicking on the element with ID ‘button-container’ on the page, all elements with style ‘banner-message’ on the page will remove the ‘display: None ‘CSS style from the stylesheet.

Using native JavaScript:

  1. Get the ID on the page is'button-container'The elements of the
  2. Gets all styles on the page with'banner-message'The elements of the
    1. Gets all the elements in the page
    2. Walk through them and filter out the style bands'banner-message'The elements of the
  3. Add the click event to the button using attachevent or addEventListener
  4. Handling click events
    1. Iterate over all'banner-message'The elements of the
    2. Iterate over the CSS style list for each element
    3. If there is one in the styledisplay:none, then remove
    4. Set up a new CSS style list for them

Using jQuery:

$("#button-container button").on("click".function() {$(".banner-message").show();
});
Copy the code

Ajax

Call the server interface/API /getWeather with the query parameter zipcode=97201 and replace the HTML of the element #weather-temp with the returned text.

Using jQuery:

$.ajax({
  url: "/api/getWeather".data: {
    zipcode: 97201
  },
  success: function( result ) {$("#weather-temp" ).html( "<strong>" + result + "</strong> degrees"); }});Copy the code

conclusion

When jQuery was invented in 2006, there was no ES5(released in June 2011). Even long after ES5 was released, not all browsers supported it. So in addition to DOM manipulation, jQuery’s big contribution during this period is to address cross-browser issues and provide convenient object and array manipulation tools such as each(), index(), and filter.

Now that ECMAScript has released the ES2021 (ES12) standard, the browser standards mess has been well addressed, and there are translation tools like Babel and new languages like TypeScript on the front end. So it’s safe to use new language features, even if ECMAScript standards are still being developed. At this point, a lot of the tools and methods jQuery provides already have native alternatives — we really prefer native implementations when there’s not much difference in usage.

In fact, jQuery uses native implementations as much as possible to improve execution efficiency. JQuery has not abandoned these natively implemented utility functions/methods, mainly for reasons of backward compatibility and browser compatibility as always – not every developer using jQuery will use a translation tool.

A common list requirement

With the development of Internet business, more and more forms of content have been moved online, and all the major Internet companies have withdrawn their own Internet tools or products.

Let’s take the most common list rendering as an example:

If we want to get a list data asynchronously from the server via Ajax, and construct different list data for presentation based on the server’s return, as shown in the following figure:

We need to generate each list item according to the return of the back end, for example, some list items have three images, some have only one image, some have no image, some have videos, some have ads. Such a list, if generated using jQuery, is a very cumbersome thing:

// The following is sample pseudocode
// Create a ul list and add it to #container
varhttpResponse = {... }; httpResponse.forEach(function (index, item) {
  // Handle the situation without images
  if (item.image.length == 0) {$("<ul>").append(
      $("<li>").append(
        $("<a>").attr("href"."#").text("first").append(
        	$("<div>").attr("class"."title").text(item.title),
          $("<div>").attr("class"."content").text(item.content),
          ... // Other divs, etc)));// There is a picture
  } else if (item.image.length == 1) {$("<ul>").append(
      $("<li>").append(
        $("<a>").attr("href"."#").text("first").append(
        	$("<img>").attr("src", item.banner),
          $("<div>").attr("class"."title").text(item.title),
          $("<div>").attr("class"."content").text(item.content),
          ... // Other divs, etc)));// There are three images
  } else if (item.image.length == 3) {$("<ul>").append(
      $("<li>").append(
        $("<a>").attr("href"."#").text("first").append(
        	$("<div>").attr("class"."title").text(item.title),
          $("<div>").attr("class"."content").text(item.content),
          ... // Other divs, etc
          $("<img>").attr("src", item.banner[0]) and $("<img>").attr("src", item.banner[1]) and $("<img>").attr("src", item.banner[2)))); }}) $("<ul>").appendTo($("#container"));
Copy the code

Such a simple list rendering, as long as there are some criteria in it, jQuery will become extremely disgusting when it is dynamically generated.

Even without the criteria, jQuery’s layer upon layer of generated nodes can be annoying when the layout of each item in a list has many levels. And the following stack of parentheses is a ** “nested hell” **, if you change one bracket level, your entire logic will report an error, which is extremely difficult to troubleshoot.

This is just a list rendering, and when you have lists, forms, multiple tabs, lexicon associations, and other functions that need to be put together and displayed together, data collaboration, you can imagine how difficult it is to build complex enterprise-level pages and interactions with jQuery.

There are a lot of clever front-end programmers at this time will start to find a new way, for example, write a variety of HTML templates in advance, and then select the required template according to the conditions, and then replace the string in the HTML template, and then render to the page after the replacement:

// The following is sample pseudocode
var templateA = "<div>{{%name%}}</div><div class='banner'>{{%bannerSlot%}}</div>";
var templateB = "<img src='{{%banner%}}'/>";
vardata = $.ajax(...) ;var listHtml = templateA.replace('{{%name%}}', data.name)
	.replace('{{%bannerSlot%}}', templateB.replace('{{%banner%}}', data.banner))
$("<ul>").html(listHtml);
Copy the code

This way, you can replace the content rendering directly in advance with the desired HTML structure, avoiding jQuery’s nested hell.

But this raises another question, complicated data substitution is very troublesome, is there a way to render the list uniformly?

JS template engine was born

As mentioned above, it is very convenient to select elements in a page using jQuery alone, but it is still very, very cumbersome to build a page structure that displays different content based on data conditions. Especially our current page, according to the back-end back to show different content needs more and more, page structure is also ever-changing, let us front-end page construction becomes very uncomfortable.

As mentioned above, some clever friends have started to write templates by themselves, and then use string search and replace, although relatively primitive, but can basically solve the pain point. Also, it would be nice to support writing JavaScript logic inside templates.

Of course, not only we think of this point, but also the Internet companies in the industry, especially around 2012, the birth of a large number of template engines, represented by:

Mustache (linkedin, Twitter, etc., still maintained today), baiduTemplate (Baidu, founded in 2011, discontinued in 2012), artTemplate (Tencent, discontinued in 2015), Juicer (Taobao, Discontinued in 2017), XTemplate, doT, Jade (it has been maintained till now, and our company is also using it now), etc

Taking baiduTemplate for example, we can easily obtain an escaped HTML content based on data and template, which has many features:

  1. Simple syntax, using Javascript native syntax, support variables, conditional judgment, loop and other uses;
  2. Default HTML escape (against XSS attacks), and support a variety of escapes including URL escape;
  3. Variable is not defined automatically output empty, prevent page confusion;
  4. Powerful functions, such as delimiter can be customized and other functions;

For example, to output a list, we can create a list item template:

<script id="liteItemTemplate" type="text/html">
<div>
    <h1>title:<%=title%></h1>
    <% if(list.length > 1) { %>
        <h2>Print list with <%= list.length %> elements</h2>
        <ul>
            <% for(var i=0; i<5; i++){ %>
                <li><%= list[i] %></li>The < %} % ></ul>
    <% } else { %>
        <h2>No list data</h2>The < %} % ></div>  
</script>
Copy the code

The template and data will be automatically compiled into the HTML we want, and XSS will be automatically escaped to avoid dangerous operations:

var data={
    "title":'Welcome to baiduTemplate'."list": ['Test1: Default support for HTML escape, such as output .'test2:'.'test3:'.'Test4 :list[5] undefined, template system will output null']};var html = baidu.template('liteItemTemplate',data);

$(".result").html(html);
Copy the code

In this way, we only need to maintain our templates, determine the data conditions in the templates, and use if to assemble the page, avoiding jQuery’s nesting hell and separating the data from the presentation.

BaiduTemplate appears to use Dom templates, which means it controls the flow (each, if, and so on) by adding tags to the Dom, and it doesn’t rely on any external template libraries. It’s probably faster, and the code is easy to read and write, and there’s no separation between markup and template, and it’s easy to see how CSS interacts with it.

Another option is a string template, as shown in the previous example. For Mustache, Jade, etc., it has to be compiled, but that allows it to be used anywhere, like on the server

The birth of modularity and the MVC framework

As mentioned above, as Internet technology continues to evolve, the business requirements required by browsers become more and more complex. Larger sites usually require a lot of page routing and a lot of modules for each page. Take Weijingdong as an example:

The amount of page routing/content, the complexity of the interaction, and the intensity of the data processing has completely surpassed that of web pages in previous years.

Check its page source code, not counting the external introduction of logical JavaScript script, only the basic page node + basic script, has reached more than 10,000 lines.

Most modern websites are composed of many small modules, and each module has its own complex data, which can be seen by users only after processing, escaping, rendering and other operations. Each module also has its own complex interaction within the module. If all of these logic is assembled by the server side, it will be a problem to develop and debug, go online, maintain later, and even affect the throughput of the server.

At this point, almost all Internet companies have reached a consensus that ** true browser-side JavaScript applications must have a proper data model and client-side rendering capabilities, not just a server processing data with some Ajax and jQuery code. You have to have a back end separation, you have to have modularity, you have to have MVC. ** It is possible to build complex and large websites only if each module handles its own JS logic, style, interaction, and is isolated from each other, and then assembled into complete pages by multiple modules.

Birth of modularity

The development of JavaScript modularity can be divided into three stages based on some characteristics. As the most pioneering representative of CommonJS in stage 2, it leads a variety of normative competition, which is conducive to development and ultimately standardization.

Stage 1: syntactic convention encapsulation

As the initial stage, some simple and crude convention encapsulation, there are many ways, advantages and disadvantages are different. Most use JavaScript language features and browser features, using Script tags, directory file organization, closures, IIFE, object simulation namespaces (such as YUI) and other methods.

These solutions solve some of the problems, but the increasingly complex front-end code and asynchronous browser loading features do not solve many of the problems, requirements and problems, the solution is naturally presented.

Stage 2: Specification development and precompilation (2009-2015)

On January 29, 2009, Kevin Dangoor published an article called “What Server Side JavaScript Needs” and created a ServerJS group in Google Groups, To build a better JavaScript ecosystem, both server-side and browser-side, and renamed itself the CommonJS Group. The CommonJS community produces a lot of modular modular Modules, which bring together a lot of different ideas and clash with each other.

This phase of development began the development of modular specifications. With CommonJS community as the trigger point, different specifications such as CommonJS (Modules/***), AMD, CMD, UMD, etc., and different Modules loading libraries such as RequireJS, sea-.js, Browserify, etc. Here the joys and sorrows of separation and union under the table.

With the advent of Browserify and Webpack tools, it is possible to write the same JavaScript module as node.js on the server side. Converting to browser-ready code via the AST is development-friendly, although it adds an additional layer of precompilation, which can be fully automated by the tools.

Some typical examples:

// 1. CommonJS Modules
// hello.js
var hello = {
		sayHi: function(){
        console.log('Hi');
    },
    sayHello: function(){
        console.log('Hello'); }}module.exports.hello = sayHello;

// main.js
var sayHello = require('./hello.js').sayHello;
sayHello();


// 2. AMD
// hello.js
define(function() {
    var names = ['hanmeimei'.'lilei'];

    return {
        sayHi: function(){
            console.log(names[0]);
        },
        sayHello: function(){
            console.log(names[1]); }}; });// main.js
define(['./hello'].function(hello) {
    hello.sayHello();
});

// 3. CMD
// hello.js
define(function(require.exports.module) {
  var names = ['hanmeimei'.'lilei'];
  module.exports = {
    sayHi: function(){
      console.log(names[0]);
    },
    sayHello: function(){
      console.log(names[1]); }}; });// main.js
define(function(require) {
	var hello = require('./hello');
	hello.sayHi();
});
Copy the code

With modular standards, although the specification is written in different ways, but it still brings a lot of convenience to developers, packaging a lot of modular packages, used between different projects, infrastructure construction is increasingly perfect, a certain degree of competition, but with the development of time, the market will choose an optimal solution.

Stage 3: Modular support at the native language level (2015-present)

Compared with the previous specification, ECMAScript standard proposed ES Modules, a modular specification for declarative syntax at the native language level in 2015. After many years, compared with the previous modular specification, it must take its essence and remove its shortcomings. The major browsers gradually realize ES Modules, in the browser that is not implemented can also be precompiled through Babel and other tools to be compatible, ES Modules gradually become the recognized standard for writing modularity in the front end.

Example:

// hello.js
var names = ['hanmeimei'.'lilei'];

export const hello = {
    sayHi: function(){
        console.log(names[0]);
    },
    sayHello: function(){
        console.log(names[1]); }}// file main.js
import { hello } from "./lib/greeting";
hello.sayHello();
Copy the code

Birth of SPA & MVC framework

Around 2012, there was also an explosion of single Page Web Application (SPA) frameworks.

SPA has many advantages over traditional pages

  1. Have good interactive experience

    It can improve the page switching experience, so that users will not frequently switch and browse the page when visiting the application page, thus avoiding page reloading;

  2. The front and back ends were developed separately

Single-page Web applications can be used in conjunction with RESTful conventions, providing interface data through REST apis and retrieving it asynchronously using Ajax, which helps separate client-side and server-side work. Furthermore, it can be divided into two parts: static page and page interaction on the client side.

  1. Reduce server stress

    The server can only produce data, regardless of presentation logic and page composition, throughput will increase several times;

  2. A common set of back-end program code

    Without modifying the back-end program code, it can be used for Web interface, mobile phone, tablet and other clients;

Represents a number of SPA frameworks launched around 2012: AngularJS, Backbone, Batman, CanJS, Ember, Meteor, Knockout, Spine, etc. All frameworks insist on view-model separation. Some emphasize MVC (Model View Control), some mention MVVM (Model View ViewModel), and some even refuse to explicitly say a third word (just Model, View, and then add something that makes them work together). The end result is similar for each framework.

Backbone.js, for example, introduces two of the most important features that have influenced most of the front-end frameworks since:

The introduction of the MVC

The most important thing Backbone does is to separate business logic (Model) from user interface (View). When the two are entangled, both logic and interface processing can be very troublesome; When the logic doesn’t depend on the user interface, it becomes very clear.

Model View
Orchestrate data and business logic Listen for changes and render the user interface
Load and save data from the server Handles user input and interaction
Events are fired when data changes Send the captured input to the model

Take a simple TAB switch as an example:

If you use jQuery to write, are filled with a lot of code to find elements, elements, value from the elements, modify the elements of the code, these pages show logic and data processing logic mixed together, you can neither quick sorting data logic, also can’t see out elements show at a glance and the logic of the switch, the whole mess:

jQuery(document).ready(function($){
	var tabs = $('.cd-tabs');
	
	tabs.each(function(){
		var tab = $(this),
			tabItems = tab.find('ul.cd-tabs-navigation'),
			tabContentWrapper = tab.children('ul.cd-tabs-content'),
			tabNavigation = tab.find('nav');

		tabItems.on('click'.'a'.function(event){
			event.preventDefault();
			var selectedItem = $(this);
			if( !selectedItem.hasClass('selected')) {var selectedTab = selectedItem.data('content'),
					selectedContent = tabContentWrapper.find('li[data-content="'+selectedTab+'"]),
					slectedContentHeight = selectedContent.innerHeight();
				
				tabItems.find('a.selected').removeClass('selected');
				selectedItem.addClass('selected');
				selectedContent.addClass('selected').siblings('li').removeClass('selected');
				//animate tabContentWrapper height when content changes 
				tabContentWrapper.animate({
					'height': slectedContentHeight
				}, 200); }}); checkScrolling(tabNavigation); tabNavigation.on('scroll'.function(){ 
			checkScrolling($(this));
		});
	});

	function checkScrolling(tabs){
		var totalTabWidth = parseInt(tabs.children('.cd-tabs-navigation').width()),
		 	tabsViewport = parseInt(tabs.width());
		if( tabs.scrollLeft() >= totalTabWidth - tabsViewport) {
			tabs.parent('.cd-tabs').addClass('is-ended');
		} else {
			tabs.parent('.cd-tabs').removeClass('is-ended'); }}});Copy the code

However, when you use MVC framework, you can effectively peel off business logic and page display logic, and also quickly know the overall operation principle of the whole project, take Backbone as an example:

// Remove all data from each TAB as Model
// ./models/tabItem.js
app.tabItem = Backbone.Model.extend({
		defaults: {
			title: 'title'.isActive: false.content: 'Content, Balabala... '
		},
		// There are also built-in data processing methods that must be used to get/set/change
		toggle: function () {
			this.save({
				isActive:!this.get('isActive')}); }});// In the TAB business module, you only need to care about the overall data changes
app.tabView = Backbone.View.extend({
		// This uses the template engine described earlier
		template: _.template($('#item-template').html()),
		initialize: function () {
      // Listen for changes to the Model and take different policies when data changes
			this.listenTo(this.model, 'change'.this.render); // re-render
			this.listenTo(this.model, 'destroy'.this.remove); // Delete your node
			this.listenTo(this.model, 'visible'.this.toggleVisible); // Hide your node
		},
		// Re-render the page elements based on the data
		render: function () {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		},
		// Hide your node
		toggleVisible: function () {
			this.$el.toggleClass('hidden'.this.isHidden()); }});Copy the code

Also, in the template, write how the page elements should be represented:

<script type="text/template" id="stats-template">
  <span class="todo-count">
    	<strong><%= remaining %></strong>
  		<%= remaining === 1 ? 'item' : 'items' %> left
  </span>
	<ul class="filters">
  		<li><a class="selected" href="# /">All</a></li>
    	<li><a href="#/active">Active</a></li>
    	<li><a href="#/completed">Completed</a></li>
  </ul>The < %if (completed) { %>
  		<button class="clear-completed">Clear completed</button>The < %} % ></script>
Copy the code

That is, the overall presentation of the page, which we went from manually selecting elements and controlling the presentation in jQuery, to manipulating data, building HTML from that data, and rendering it to the page. Each time the data is changed, the render function is triggered, and the framework builds a new HTML from the new data + template, removing the old HTML and mounting the new HTML. Using a graph example:

Or:

Backbone also introduces the concepts of Collection and controller. Later controller is renamed router. It is not expanded here.

Event delegation

Seeing this, you may have noticed a BUG in the MVC model above, which is that in addition to rendering pages frequently, I need to rebind events frequently if I have event bindings in my HTML:

What’s wrong with this question is that:

The content of the page changed, so frequent apply colours to a drawing is no problem, but binding events in the history of the elements, because the old HTML node was removed in lead to new nodes are also required to bind a, if little event listeners, can accept, but if the event is more, you have to write a function for the event binding, And call it frequently.

As follows:

rebindEvent: function () {
  this.allCheckbox = this$('.toggle-all') [0];
  this.$input = this$('.new-todo');
  this.$footer = this$('.footer');
  this.$main = this$('.main');
  this.$list = $('.todo-list');

  this.allCheckbox.on('add'.this.addOne);
  this.$input.on('reset'.this.addAll);
  this.$footer.on('change:completed'.this.filterOne);
  this.$main.on('filter'.this.filterAll);
  this.$list.on('all', _.debounce(this.render, 0));
},
Copy the code

This may seem like no problem, but when pages render frequently, it can be a huge performance challenge for the browser.

Backbone introduces an event delegation mechanism, binds all events involved in the page to its parent element (page mount node), and responds to related events by the parent element through bubble mechanism. Since the parent element is not removed, only one binding is required to render frequently.

The following code:

app.AppView = Backbone.View.extend({
		// In which page element the entire app instance is mounted (rendered)
		el: '.todoapp'.statsTemplate: _.template($('#stats-template').html()),
		// Monitor all events in app and respond to them
		events: {
			'keypress .new-todo': 'createOnEnter'.'click .clear-completed': 'clearCompleted'.'click .toggle-all': 'toggleAllComplete'},... Other logic});Copy the code

Complex requirements for a large form linkage

It seems that the Model + Template → View pattern can handle all development scenarios. But consider two scenarios:

  1. Your page, 10000 pairs of data (e.g., twitter traffic), after a request, you need to modify some differentiation in each data content (such as comments, thumb up quantity, etc.), at this point, you have to complete to render 10000 data, generate new HTML, and then delete the original article 10000 page elements, Then insert the new element. On your browser, each render session may take 10 seconds to render new content.
  2. You have a complex background form that has cascading relationships with each other and dependencies between data. If an option changes, you need to change the data and then re-render the related form items associated with that data. And the data that the user filled in will be lost and you’ll have to manually restore it.

Cases of large data volumes like 1 May not be common, but cascaded forms are very common in our daily development. Examples of takedown diagrams:

  1. Each form item itself has linkage relationship, such as regional cascade control
  2. When you select one option, it affects the presentation of another option, validation, and data collection
  3. The content I have filled in before cannot disappear and be filled in again after the page is rendered again
  4. When I submit, I want to collect all the data of my current selection, not some irrelevant empty data

Let’s look at a simple cascading component developed in jQuery:

$(function(){
  var level1 = [{id:20000.name:'Technical professionals'.pid:20000.lv:1}, ...others];
  var level2 = [{id:10100.name:'Head of China's COMMUNIST Party organ'.pid:10000.lv:2}, ...others];
  var level3 = [{id:10201.name:'Person in charge of the organ of State power'.pid:10200.lv:3}, ...others];
  var level4 = [{id:'1A'.label:'All kinds of professional and technical personnel'}, ...others];

  var professionStr1 = '';
  var professionStr2 = '';
  var professionStr3 = '';
  var professionStrOne = professionStr1;
  var professionStrTwo = ' ';
  var professionStrThree = ' ';
  for(var i=0; i<level1.length; i++){ professionStrOne +='<option value="' + level1[i].id + '" >' + level1[i].name + '</option>';
  }
  $(".professionOne").html(professionStrOne);
  $(".professionOne").change(function(){
    professionStrTwo = professionStr2;
    if($(this).val() ! ='-- Please select occupation type --') {var professionTwoPid = new Array(a);for(var j=0; j<level2.length; j++){if (level2[j].pid == $(this).val()) {
            professionStrTwo += '<option value="' + level2[j].id + '" >' + level2[j].name + '</option>'; professionTwoPid[j] = level2[j].pid; }}if(professionTwoPid.length == 0) {for(var l=0; l<level1.length; l++){if(level1[l].id == $(this).val()){
                    var professionOneValue = level1[l].name;
                }
          }
          professionStrTwo = professionStrThree = '<option value="' + $(this).val() + '" >' + professionOneValue + '</option>';
          $(".professionTwo").html(professionStrTwo);
            $(".professionThree").html(professionStrThree);
        }else{$(".professionTwo").html(professionStrTwo);
            $(".professionThree").html(professionStr3); }}else{$(".professionTwo").html(professionStr2);
      $(".professionThree").html(professionStr3); }}) $(".professionTwo").change(function(){
    var professionStrThree = professionStr3;
    if($(this).val() ! ='-- Please select a profession --') {var professionThreePid = new Array(a);for(var k=0; k<level3.length; k++){if (level3[k].pid == $(this).val()) {
            professionStrThree += '<option value="' + level3[k].id + '" >' + level3[k].name + '</option>'; professionThreePid[k] = level3[k].pid; }}if(professionThreePid.length == 0) {for(var m=0; m<level2.length; m++){if(level2[m].id == $(this).val()){
                    var professionTwoValue = level2[m].name;
                }
          }
          professionStrThree = '<option value="' + $(this).val() + '" >' + professionTwoValue + '</option>';
          $(".professionThree").html(professionStrThree);
        }else{$(".professionThree").html(professionStrThree); }}else{$(".professionThree").html(professionStr3); }})});Copy the code

Basically nothing!

Backbone MVC framework implementation I will not show, but we should also think, every time the user choose the first level, to obtain the corresponding second level of data, and replace the second level of the Model, the page will automatically render the second level; When the user selects level 2 and changes the level 3 Model, the page will automatically render level 3. And so on.

app.AppView = Backbone.View.extend({
		// For all cascading selections, the change event is triggered
		events: {
			'change .profession': 'changProfession'
		},
    changProfession: function (e) {
      // Put the next level of data into the Model
      this.model.set({
        e.index + 1: this.data[e.value]
      });
  		// Clear all lower-level data
  		// For example, I selected level 4 before, but this time I changed level 1, so the data of level 3 and level 4 previously selected should be cleared
  		this.model.clearAfter(e.index); }});Copy the code

You just need to focus on how the data is handled, not how the page generates the Dom. It’s that elegant.

Data binding and differentiation update technology

Let’s start with a very common case:

After we change the supplemental business information, its subsequent form content will change. Previously, we have talked about the collaborative Render of MVC Model and View, which can be very convenient to deal with the change of page data.

But one important point here is that our template is the entire form, and once one of the data changes and is rerendered, the rest of the user’s fields will disappear and we need to manually restore them.

After render, we must manually restore the data:

app.AppView = Backbone.View.extend({
    render: fucntion () {
      this.$el.html(this.template(this.model.toJSON()));
			this.updateViewData();
			return this;
    },
    updateViewData: function () {
			this$('.new-todo0').val(this.model.get('a'));
      this$('.new-todo1').val(this.model.get('b'));
      this$('.new-todo2').val(this.model.get('c'));
      this$('.new-todo3').val(this.model.get('d')); }});Copy the code

Of course, every framework has its own improvement scheme, such as Backbone JS provides the concept of collection:

In the above case, we can use collection, that is, each form field has its own separate Model. Although it is troublesome to write code, it can avoid data loss and manual assignment.

So, since writing a Model is such a hassle, is there a Model that can handle the whole form associative rendering situation?

Vue and React are differentiated updates

This brings us to our most popular frameworks: vue.js and React. They have many, many features that solve many, many problems that we won’t go into. Vue and React can Render data without affecting the user’s completed data, and do not need to manually restore the data.

They do this using virtual Dom technology, as shown below:

During the page Template compilation phase, they automatically recognize the relationship between the Template code block and the Model data, and generate the Render function specific to the corresponding data. When a piece of data changes, the Render function involved in the data is executed and a new virtual Dom node is obtained.

As shown in the figure, when a certain data in the Model changes, Vue will only generate the associated part of the virtual Dom for differentiated update, rather than replacing the whole form.

In addition, if the content associated with this data contains multiple page nodes, Vue will automatically diff with the previous virtual Dom after rendering and generating a new virtual Dom. Find the actual page nodes that have changed and differentiate them:

If our entire listData is reassigned, Vue will render a new virtual Dom based on the new data, and then diff it against the previous virtual Dom. After diff, if only one number has changed, Vue will find only that number on the page and change only one number. How efficient! Imagine the time and performance savings if the list had 10,000 pieces of data.

In addition, Vue’s differentiated update is a great boon to complex form systems such as merchant system, qualification system and PaaS system. There are also a large number of UI component libraries based on Vue and React on the market, which encapsulate form systems, data verification, etc., and cooperate with Vue templates, slots, filters, and two-way data binding, greatly improving our development efficiency.

The full text summary

In fact, you already know that Vue/React and jQuery are not comparable at all. They are products of a different era.

JQuery can only be thought of as a library of tools designed to smooth over the differences between browsers like Internet Explorer and Chrome a decade ago. In addition, it also provides a good page element selector, you can quickly select the elements in the page. As browsers continue to upgrade, the differences between browsers have been almost wiped out, and many of the tools jQuery provides have been built into the browser native tools, which are much better than jQuery because of native support.

JQuery has no modularity, no MVC data/presentation separation, no tool functions to assist modern development, and no systematic UI component library. Everything is the most primitive and difficult to carry modern front-end development tasks.

Using the Vue/React Modernization framework, you will have:

MVC architecture

Business logic and page presentation logic are completely separated, making it easier to understand each other’s logic and process, facilitating development/maintenance

Independent data Model, centralized data collection and processing

Template rendering

Avoid manual assembly of page structures that create nesting hell, and avoid writing a bunch of presentation logic inside your business logic

modular

Divide pages into modules and components, introduce and package them as needed, and maintain them structurally

Differentiation update

Avoid meaningless rendering, improve overall performance, and avoid loss of data and event listeners due to Dom manipulation

UI framework and tool library

The community has a large library of tools and UI libraries for Vue and React, right out of the box

other

You also have SPA, Store, front-end routing, and more. In addition, you can use NPM ecology such as WebPack. HMR, tree-shaking, etc. will greatly improve your development efficiency.