前端技术演进发展简史

前言:为什么要了解历史

以铜为鉴,可以正衣冠 ,以人为鉴,可以明得失,以史为鉴,可以知兴替(李世民)。
如果说我看得远,那是因为我站在巨人的肩膀上(牛顿)。
了解一门技术的历史,可以帮助我们从历史的角度来看技术演进发展,理解前端技术为何会变成现在的模样,理解技术社会之间的联系,从历史的更大的视野的层面来理解技术。

一、前端起源

1990 年,第一个web浏览器诞生,Tim 以超文本语言 HTML 为基础在 NeXT 电脑上发明了最原始的 Web 浏览器。
1991 年,WWW诞生,这标志着前端技术的开始。
在开始之前先看看什么是前端

  • 现在的前端其实是个很大的范畴(web,移动端(Hybrid App),游戏,桌面端(electron.js, NW.js),小程序等)。
  • web前端开发:针对浏览器的开发,代码在浏览器运行,它实质是前端代码在浏览器端被编译、运行、渲染成页面。前端代码由HTML、CSS、 JavaScript构成。
  • 后端:针对服务器的开发,代码在服务器运行。

二、前后端不分的时代

初期静态网站

互联网发展的早期,WWW(World Wide Web)、浏览器、JavaScript相继诞生,最开始大多是HTML静态网页。

动态网站技术阶段

比较有代表性的技术有JSP 、PHP、ASP、ASP.NET 等语言,它们都类似,是运行在服务端的语言。
那时候没有专业的前端,前后端开发是一体的,前端代码是后端代码的一部分,前端写静态模板,后端加数据套模板。

浏览器展现页面的流程是:
  • 1、后端收到浏览器的URL请求,后端路由响应
  • 2、后端生成静态页面
  • 3、发送到浏览器渲染成页面
后端 MVC 的开发模式

那时的网站开发,采用的是后端 MVC 模式。

  • Model(模型层):提供/保存数据
  • Controller(控制层):数据处理,实现业务逻辑
  • View(视图层):展示数据,提供用户界面
    前端只是后端 MVC 的 V,那时候前端的 V 是在服务端渲染的。
    PHP,ASP,ASP.NET,JSP等都是典型的这样的模式;
JSP页面长这样:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<p>
   今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
</body> 
</html>
PHP模板
<h1>Car {{ $car->id }}</h1>
<ul>
  <li>Make: {{ $car->make }}</li>
  <li>Model: {{ $car->model }}</li>
  <li>Produced on: {{ $car->produced_on }}</li>
</ul>

三、AJAX诞生

AJAX诞生是前端发展的一个里程碑,Ajax 技术诞生,改变了一切。

  • 1999年,微软公司发布IE浏览器5.0版,第一次引入新功能:允许JavaScript脚本向服务器发起HTTP请求。这个功能当时并没有引起注意,直到2004年Gmail发布和2005年Google Map发布,才引起广泛重视。
  • 2005年2月,AJAX这个词第一次正式提出,指围绕这个功能进行开发的一整套做法。从此,AJAX成为脚本发起HTTP通信的代名词。
  • 2006年W3C发布了它的国际标准。
AJAX是基于现有的Internet标准,并且联合使用它们:

XMLHttpRequest 对象 (异步的与服务器交换数据)
JavaScript/DOM (信息显示/交互)
CSS (给数据定义样式)
XML 、JSON(作为转换数据的格式)
lamp AJAX应用程序与浏览器和平台无关的!
在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。
Google Suggest 使用 AJAX 创造出动态性极强的 web 界面 当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。

AJAX 如何工作
ajax.png
AJAX使用的进化
  • STEP1:XMLHttpRequest 原生对象
var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);
request.onload = function() {
  if (request.status >= 200 && request.status < 400) {
    // Success!
    var data = JSON.parse(request.responseText);
  } else {
    // We reached our target server, but it returned an error
  }
};
request.onerror = function() {
  // There was a connection error of some sort
};
 //  send request
request.send();
  • STEP2:$.ajax 操作
$.ajax({
    type: 'GET',
    url: '/my/url',
    data: data,
    success : function(result){
        //TODO RESULT
    }
});
  • STEP3:Promise 操作
let getData = function (url) {
    return new Promsie(function (resolve, reject) {
        $.ajax({
            type: 'GET',
            url: url,
            success: function (data) {
                resolve(data);         
            },
            error: function (err) {
                reject(err);
            }
        });
    });
};
 
var data = getData('/my/url').then(function (data) {
     //TODO DATA
});
  • STEP4:生成器 Gererator (koa1 使用了此函数)
let it = null;
let ajax = function(url,data){
    $.ajax({
       type: 'GET',
       url: url,
       data: data || {},
       success : function(result){
            it.next(result);
       }
    });
};
 
function *getData(){
    var data = yield ajax('/my/url');
    console.log('data=',data);
};
 
it = getData();
it.next();
  • STEP5:Async/Await 高级操作 (koa2使用了async函数)
let ajax = function(url,data){
    return $.ajax({
       type: 'GET',
       url: url,
       data: data || {}
    });
};
 
async function getData(){
    var data = await ajax('/my/url');
    console.log('data=',data);
};
 
getData();

四、前后分离时代

1、jQuery 时代(开始注重前后端分离)
  • 2006年,jQuery发布,它当时的竞争对手很多:Dojo、Prototype、ExtJS、MooTools。
    那时jQuery的宣传口号仅能说是它的性能上升了100%、200%、300%。
  • 2009年,Sizzle选择器引擎研发成功,jQuery才取得压倒性的优势。
    当时前端界首要面对的是浏览器兼容性问题,jQuery在处理DOM兼容上真是知微见著, 发掘出大量的DOM/BOM兼容方案(例如Dean Edwrad的addEvent(), IE的px转换方案,domReady的doScroll方案,globalEval的兼容方案等)

jQuery也打破了前端开发者的编程思维,之前是按照后端的开发思路来的:做一个业务就先封装一个类,有了这个类后,再想办法传入一个DOM,然后再通过类方法操作DOM。而jQuery是DOM为中心,开发者可以选一个或多个DOM,变成jQuery对象,然后进行链式操作。当时为了改变用户的思维,国内的高手写了不少文章来引导大家。
其次,开发者们已开始注重前后端分离,并要求不能污染Object原型对象,不能污染window全局变量。这样,jQuery只占用两个全局变量。
再次,jQuery非常轻量级,采用Dean Edwards编写的Packer压缩后, 大小不到30KB。并且里面实现得非常精妙,以令人瞠目的手段解决各种兼容痼疾。
为了学习这些技巧,高手们翻了一遍遍jQuery的源码,所以网上有大量关于其源码详解的书藉。甚至前端工程师在面试时也会被考到jQuery的源码实现,这样,jQuery在国内更加流行。

jQuery的流行间接带来以下的发展:
  • 促使人们对CSS1~CSS3选择器的学习
  • 促进了浏览器原生选择器引擎document.querySelectorAll、Element.matches的诞生
  • 提高人们对domReady(DOMContentLoaded事件)的认识
  • 促进了Promise与requestAnimateFrame 的诞生
    最重要的是降低前端门槛,让更多人进入这行业,前端工程师的队伍越来越壮大。
    这样的话,不断涌现出优秀的工程师,他们创造了大量jQuery插件与UI库。为后jQuery时代,人们研发前端模块加载、统一异步机制、 打造大型MVC框架, 甚至伸向后端,接管打包脚本而发明Node.js,来腾出大量时间。

这个时期涌现了大量jQuery-like的库,其中最著名的是Zepto.js。Zepto的出现也标志着我们进入移动互联网时代。那时配套出的著名库还有iScroll、fastclick、Lazy Load、Modernizr、fullPage。

随着社会的发展jQuery存在的问题:

jQuery的链式操作风靡一时,也带来许多问题,当Ajax出现依赖时,就不可避免就出现回调地狱。因此针对这方面的讨论,诞生Deffered与Promise。有关回调地狱的讨论,在后来讲Node.js异步处理时,将会再一次热烈地讨论。

  • 回调地狱
// Demonstrates nesting, CPS, 'callback hell'
 $.get('api1/data', function(resp1) {
     // Next that depended on the first response.
     $.get('api2/data', function(resp2) {
         // Next request that depended on the second response.
         $.get('api3/data', function(resp3) {
             // Next request that depended on the third response.
             $.get(); // ... you get the idea.
         });
     });
 });

jQuery如此多的选择器不好维护,随着社会的发展,页面的交互也越来越复杂,造就了Web Page向Web App进化,新的趋势带来新的开发方式。

前端的发展离不开浏览器的发展
  • 浏览器现状


    llqxz.png
  • 浏览器内核


    llqnh.png
值得一提的是V8引擎(JS虚拟机):
  • 2008年9月2日,Google的chrome浏览器发布,一并发布的Js引擎,就是V8引擎。V8使用BSD协议开源。
  • V8引擎使用 C++ 开发,将JavaScript编译成了机器码,而不是字节码,还用很多优化方法提高性能,因此,V8引擎 速度非常快。
  • V8引擎还可以独立运行,可以嵌入到其他任何C++程序中,使在服务端运行JS成为可能。
  • 2009年,基于V8引擎,诞生了Nodejs,这是服务器端运行JS的运行环境。
    google的V8意义重大,它间接催生了,前端工程化。
2、前端模块化阶段(后jQuery时代、node.js诞生)

jQuery的出现让前端工程师开发更加轻松,假如工程师想实现一个功能,搜索出一个jQuery插件来实现。那时候大家在前端网站就整天介绍jQuery插件,很少讨论一些底层的实现。

同时也冒出很多新的问题:
  • 前端工程师通常编写一个页面,会引入十多个乃至几十个jQuery插件,页面上塞满了Script标签。众所周知,浏览器是单线程,Script的加载,会影响到页面的解析与呈现,导致著名的白屏问题(当时前端用力过猛,body中的所有东西都是动态生成的)。
  • jQuery另一个问题是全局污染,由于插件的质量问题,或者开发的素质问题,这已经是IIEF模块或命名空间等传统手段无法解决了。

于是一些优秀的前端工程师们决定向后端取经,引入模块机制。早期,这种模块机制在Dojo、EXT这些框架中都是内置的,但是显然说服不了另一个框架的用户用对方的模块机制,于是有人立志要统一这种模块定义方式,成立了CommonJS。CommonJS诞生很久一段时间后,在后端的Node.js出现时才有用武之地。

CommonJS

CommonJS规范是诞生比较早的。NodeJS就采用了CommonJS。是这样加载模块:

// clock.js 定义
module.exports ={
  satrt:function(){}
}
// 引用
var clock = require('clock');
clock.start();

但不料,CommonJS内部也有派系,谁也说不服对方。终于有一个人忍不住自己独立开发出RequireJS,其模块规范即为AMD。AMD最大的优势是它支持各种插件,且简单明了,并且提供shim机制加载以非AMD规范编写的JavaScript代码。

AMD

AMD,即 (Asynchronous Module Definition),这种规范是异步的加载模块,requireJs应用了这一规范。先定义所有依赖,然后在加载完成后的回调函数中执行:

// 定义
define(function () {
    return {
        attr1: 'attr1',
        attr2: 456,
        start:function(){}
    }
});
// 引用
require(['clock'],function(clock){
  clock.start();
});

AMD虽然实现了异步加载,但是开始就把所有依赖写出来是不符合书写的逻辑顺序的,能不能像commonJS那样用的时候再require,而且还支持异步加载后再执行呢?
而国内,则流行另一种规范风格,背靠阿里的大旗,有人推出了SeaJS,号称其规范为CMD。其实无论国内还是国外,都产生许多模块加载器,但最后还是被淘汰了,规范一个就够了,不宜过多。

CMD

CMD (Common Module Definition), 是seajs推崇的规范,CMD则是依赖就近,用的时候再require。它写起来是这样的:

define(function(require, exports, module) {
   var clock = require('clock');
   clock.start();
});
还有一种模块引入方法 ES6 import 、export

但是前端工程师的创造力就是这么惊人,从无到有,再到泛滥成灾,一年足矣。这可能与前端代码是开源的原因。最后有人统一了前两种规范(AMD、Node.js模块),同时还支持老式的“全局”变量规范。
自此,JavaScript开发模式焕然一身了,大家只要在代码外面包一层就可以全世界通用,不用担心全局污染的问题。
其次,jQuery开发者需要解决大段HTML的生成问题,之前jQuery有.html,.append, $before等方法,可以将一大段符合HTML结构的字符串转换成DOM再插入到页面上。
但现在我们想分离出来,让HTML独立到不同的文件中,然后插数据,这就是前端模板。前端模板的情况与模板规范一样,从没有到多如芝麻的境地。这时筛选一个好用且性能高的模板是一件让前端工程师头疼的问题,那时网上有许多评测文章来介绍它们。
前端模板技术可以用一个公式来描述:
HTML = template(vars)
有了前端模板后,又诞生了前端路由,基于它们,人们发明一个新词汇SPA。作为这个时代的尾声,来自Ruby界的高手Ryan Dahl发明了Node.js。前端工程师们欢呼:可以不用传统的后端就能自己写一个网站了!
Node.js的发展就不详述了,很快它就冒出海量模块、路由、状态管理、数据库、MVC框架都有了。这时,前端就缺自己的MVC框架了。Node.js转眼就十岁生日了。

3、MVC, MVVM,SPA、小程序(前端工程化阶段)

在大量的MVC与MVVM框架中。最先火起来的是Backbone.js,使用纯正的MVC模型, Backbone.js是jQuery最后的支持者,它强依赖于jQuery。
Backbone.js的作者还搞了另一套编译语言CoffeeScript, 里面的箭头函数、类机制、 解构赋值等语法糖都深深影响了后来的ES6。

前端MVC

传统的MVC主要分为三部分

  • View 传送指令到 Controller
  • Controller 完成业务逻辑后,要求 Model 改变状态
  • Model 将新的数据发送到 View,用户得到反馈
mvc.jpg

MVC简单实现

function Model(value) {
    this._value = typeof value === 'undefined' ? '' : value;
    this._listeners = [];
}
Model.prototype.set = function(value) {
    var self = this;
    self._value = value;
    setTimeout(function() {
        self._listeners.forEach(function(listener) {
            listener.call(self, value);
        });
    });
};
Model.prototype.watch = function(listener) {
    this._listeners.push(listener);
};
Model.prototype.bind = function(node) {
    this.watch(function(value) {
        node.innerHTML = value;
    });
};

function Controller(callback) {
    var models = {};
    var views = Array.prototype.slice.call(document.querySelectorAll('[data-bind]'), 0);
    views.forEach(function(view) {
        var modelName = view.getAttribute('data-bind');
        (models[modelName] = models[modelName] || new Model()).bind(view);
    });
    callback.call(this, models);
}


// html:
<span data-bind="hour"></span> : <span data-bind="minute"></span> : <span bind="second"></span>

// controller:
new Controller(function (models) {
    function setTime() {
        var date = new Date();
        models.hour.set(date.getHours());
        models.minute.set(date.getMinutes());
        models.second.set(date.getSeconds());
    }
    setTime();
    setInterval(setTime, 1000);
});

接着下来是谷歌的Angular,微软的Knockout.js,苹果的Ember.js这三个MVVM框架,MVVM就是比MVC多一个数据绑定功能,但这数据绑定功能是非常难实现。Knockout是使用函数代替属性的技巧实现,它的设计影响到后来的Mobx;Ember.js是基于Object.defineProperty;Angular是将函数体转译成setter()、getter()函数。

大公司将后端开发经验挪用过来,用Node.js开发了一套CLI,里面包含了脚手架生成, 打包脚本、语法风格检测、环境变量插入,代码复杂度检测,代码提交时自动跑单元测试, 图片与JS压缩等功能。ESLint、JSLint、JSHint、CSS Lint、 htmllint等就是那时期出现的。

但CLI的出现导致了前端的分裂,以前大家都使用jQuery,但自CLI帮你建好项目的那一刻起,就将你划归某一子阵营,你是Angular?Ember.js?还是jQuery?对了,jQuery没有大公司支撑的阵营被快速边缘化。

对于个人开发者,他们是没有能力开发这么功能完备的CLI,于是出现了Code Climate、Travis CI、CircleCI这样的平台。它们的出现标志着jQuery小作坊时代的终结了。

前端开发者也出现分化:有些人转向后端,出现了CNode的门户网站。另外一些人开始搞工程化。一时间出现上百种构建工具,出名的有Grunt、Gulp、FIS3、webpack、 Rollup、npm-script。

你方唱罢我登场,这些构建工具均会经历时代的考验,如大浪淘沙般,最后存活得仅为寥寥。现在使用较多的webpack,Rollup。

jQuery的时代一去不返了,再没有人关心拖了N年的Bootstrap 4终于发布了,没有人知道jQuery3.5的瘦身计划,也没有人问jQuery的源码,渐渐地,大家不关注jQuery的工具链了。

以React, Vue, Angular为代表的前端框架,造就了如今SPA(single page application)的大势所趋势。同时React - React Native, Vue - Weex,node.js,各种小程序等也正在拓展前端的边界。
SPA 单页面应用原理
  • 什么是SPA? SPA 即单页面,就是页面整体不刷新,不同的页面只改变局部的内容的一种实现方式。
  • 浏览器URL,location.hash部分发生变化,页面不会重新请求,其它参数变化,均会引起页面的重新请求,而在Js中恰恰有事件 window.onhashchange 能监听到 location.hash的变化,于是就利用这个原理来达到一个修改局部内容的操作(vueRouter就是利用这一原理实现的,还有HTML5,history.pushState实现history模式)。
<!DOCTYPE html>
    <head>
        <script type="text/javascript">
            window.onhashchange = function(){
                var page = location.hash;
                if(page === '#home'){
                    document.getElementById('main').innerHTML = '这是首页';
                    return;
                };
                
                if(page === '#help'){
                    document.getElementById('main').innerHTML = '这是帮助页面';
                    return;
                };
                document.getElementById('main').innerHTML = '404';
            }
        </script>
    </head>
    <body>
        <header>
            <a href="#home">首页</a>
            <a href="#help">帮助</a>
        </header>
        <article id="main"></article>
    </body>
</html>
单页面应用的问题:
  • 对现有的搜索引擎不友好
  • 首页加载速度变慢
    于是,为了解决这个问题,前端又把网页搬到后端去渲染了,出现了,服务端渲染(SSR: server side render)只是这次不一样的后端渲染,跟JSP,PHP,ASP不一样了,现在可以前后的分离开发,一套后台多端使用,前后端代码解耦,专业的人做专业的事!

什么是服务端渲染
简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。
需要SEO的程序,就需要SSR,但是,SSR会让服务器的开销增加,服务器压力比较大。

webServer(可以用node服务),CGI:(Common Gateway Interface)公共网关接口,CDN,交互图:
  • 1、红圈1表示SSR
  • 2、红圈2表示浏览器渲染


    timg.jpg

五、结语

在前后不分的时代,由于静态网页完全满足不了社会的发展对网页的需求,于是,由后端工程师主导的PHP,JSP,ASP的动态网页诞生了,但是服务端渲染有很多的弊端,服务器压力大,前后端代码耦合高,交互差,页面的交互需要刷新整个网页,2005年Ajax诞生,改变了一切,前端走上了第一个里程碑式的时代,前后的分离开始注重,jQuery风靡一时,它的成功是前端人的一代记忆,各种jQuery插件层出不穷,问题页诞生了,各种插件的全局变量污染,jQuery的链式操作的回调地狱,导致了模块化,延迟对象等新技术的提出,2009年node.js诞生,催生了前端工程化,react,vue,anguler等MVC,MVVM框架的流行让前端SPA成为大势所趋!
前端技术的发展,是在不断的解决问题,诞生新的技术,是社会在不断发展中催生了新技术,同时新技术又促进社会的前进,相互交织,螺旋前进!
本人学识有限,难免会存在理解错误的地方,望码友高逼格指正,勿喷。

参考资料:
前端的发展历程
大前端的技术原理和变迁史
前端发展简史
前端开发进化史,你经历过哪几个时期
等等!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容