原文:https://closebrace.com/articles/2017-09-11/a-brief-incomplete-history-of-javascript
我们从哪里开始, 当下在何处, 如何走来, 并且...为什么?
Introduction - 简介
在2017年,无论是新手还是满身疲惫的老兵,都在JS开发中对这门语言掂量着:从何入手以及该选哪条路呢?大伙热衷于热门技术,但通常对它们为什么那么好(或为什么不是别的)并没有理解。理解JS的历史可以帮助我们搞清它当今的状态。
先来聊聊问题。所有语言写就的所有程序,都在解决问题。在宏观维度(“如何向用户交付一个解决方案”)、中等维度(“如何快速有效的排序数据”),或微观维度(“怎么遍历数组”)上,都在纠结这个。编程语言就是用来让用户解决这些问题的工具,而用在web或其他地方的JS自然也没有什么不同。有些人乐于细数JS的种种不是,我也不否认确实有很多问题,但对于其他语言来说也是这样的。反正我是从来没见过哪个经验丰富的开发者周期性的抱怨一些早期标准的,因为多说无益嘛。
这篇文章并不会深入详尽的着眼于JS解决的所有问题,更非如何去解决这些;而是在一个大的尺度上去概览历史 -- 包括语言本身的和其曾用来解决web上不断增长的复杂问题的方法。要是真的说尽这门语言详尽的历史,那足够写完一本书了;而本文只尝试对“我们在哪?”和“我们为什么在这?”这类问题给出大体和不失水准的回答,这也是标题叫做“简史”的原因。
如果不了解当时的基本情况,就不容易领会“什么是框架”和“为什么jQuery适合解决A问题而非B”这类常见问题。对这些问题的探索会让你成为一个更机灵、有见识的开发者,从而省下大量精力。
这篇文章按四个主要时期划分:早期时代--新兴的语言在浏览器中可用的十来年;jQuery时代--当jQuery和其他框架横空出世以应对JS开发中一些基础并头疼的问题的年代;单页应用时代--当开发者遇到了jQuery的瓶颈并用Backbone和AngularJS等框架获得显著提升的年代;现代时代--在此期间,精心编写的智能化框架大量出现,更关注速度、易用和模块化,并回归原生JS。对于每个时期,将介绍一些当时的web开发的历史背景和当时人们遇到的问题,并解释当时的技术如何应对这些问题。
我们正在自我超越,让我们乘坐时光机,回到恐龙制霸地球以及......浏览器一家独大的时代:Netscape Navigator
The Early Era - 早期时代
时间轴: 约在 1996 – 2004 问题: 基本 DOM 操作, 用户交互 创新: JavaScript本身, XHR 和 AJAX 主要浏览器: Netscape Navigator, Microsoft Internet Explorer
JavaScript 是 Brendan Eich 花了十天左右创建出来的, 作为 Mozilla 的一位员工,他被雇佣来将 Scheme 编程语言引入 Netscape Navigator 浏览器中。然而这个计划被一种语法更接近Java的语言取代了。Eich 创造了 LiveScript,一种可以直接嵌入HTML文档并可以无需编译就被浏览器直接处理的语言。LiveScript 最初在 1995 年 9 月随 Netscape Navigator 发布,并在当年 12 月发布的第三个版本中更名为 JavaScript。[1]
尽管 JavaScript 这个名字沾了点 Java 的光,但除了有接近C的语法、缩进无关的、面向对象等特性这点儿共通之处外,它既不能和 Java 共享代码库,在语言核心方面也明显是完全不同的。这命名是个商业决定,并导致了接下来的二十多年中,对于 JavaScript 开发者的招聘接洽中充满了“有大量可用 Java 编程机会”的宣传...谢谢啊,Mozilla!
在最初几年中,JS和微软的几种脚本语言一决高下,带来的显著影响就是,网站要么在 Netscape 下工作正常,要么在 Internet Explorer 下(当时发布了其第三个版本)显示的不错,但不能两者兼顾。
无疑,网景公司在这些年一时无两,看起来不可阻挡。Netscape 3,特别是接下来的 Netscape 4 两个版本,成为了其巅峰时刻,它们击碎了所有挑战者的下巴。IE 则是个即便 CSS 已经流行的情况下却连 HTML 都渲染不好的落选者。
但在21世纪初期,Netscape 的开发失去了活力,而 IE 持续改进(从IE5开始,接下来是5.5,然后是神挡杀神的IE6),并获得了更大的市场份额。JS的开发在这个时期是有限的 -- 一方面包括 Mozilla 和微软(把自家脚本命名为“JScript”以避免版权问题)在内的厂商开始尝试推动并引领了标准化,另一方面浏览器的兼容性也大量显现。
在 1999 年的 Netscape 4 中 PlanetQuake 的存档版本。使用了JS在主图像下滚动新闻标题 ,太厉害了...
由此带来的后果就是,编写在不同浏览器下都能工作的脚本复杂而冗长,甚至很多情况下完全不可行。那阵子很多脚本都只能作为锦上添花的小功能。React Armory 网站的创建者 James K. Nelson 说:“那时为了给我建的网站菜单栏上增加一个鼠标经过的图片效果,我使用了JS。并用它创建不那么好用的下拉菜单和有一些简单动画的烦人弹出框”。
讨厌的滚动文字、弹出提示、确认框和很多安全验证充斥着那时的网页。此外,可能那时最常见的一个JS用处就是创建图片过渡等 DHTML 效果,其中很大一部分功能后来被CSS取代。
还是有人在JS领域取得了卓越的成就。《JavaScript: Visual Quickstart Guide》的作者,也是那个时代的开发者 Dori Smith 提到:“90年代后期有大批JS框架和库,Nick Heinle 和 Steve Champeon 各自有一个具有代表性的。但是这些库都依赖于作者本身去保持更新,这对任何人,还要同时开发网站的话,都挺困难的”。找到这些库同样困难,少有人知。当在web上实现动态交互时,占主导地位的是 Java applets、ActiveX widgets,和 Macromedia Flash。
事情在 2000 年后有了转机,并取得了一些幸运的进展,造成了JS的真正腾飞。众多成就中的一件事情就是由JS驱动的前端和后端服务器之间的异步通讯,包括最终被所有主流浏览器接受的 XMLHttpRequest (XHR)。其他还有稍后出现的一众开发框架,如 Prototype、 MooTools 以及不得不提的 jQuery。
The jQuery Era - jQuery时代
时间轴: 约在 2004 – 2010 问题: 网站复杂度的增长, 太多的浏览器要适配 创新: 健壮的 DOM 操作, 早期的单页应用 主要浏览器: Microsoft IE, Mozilla Firefox
在21世纪初期,DHTML 开始变得流行。D代表着动态,也基本意味着“直接在HTML上搞点什么,而不用刷新浏览器”。这在当下看起来滑稽可笑,但在当时确是个大事情。传统上,当需要做点什么时,都需要网站刷新才行。JS提供了一些玩具功能,但标准网站很大程度上还是基于页面的。当用户点击一个 tab 时,用户会被带到一个新页面,或者是在HTML重新渲染之前调整模板参数变量并刷新整个页面。
在这个时期中,只有两种主要的浏览器:微软的IE6--一种发布时难以置信但最终竟变为勒住互谅网脖子的行尸走肉的浏览器;以及 Mozilla 的 Firefox 。但是也有IE的其他版本在使用。“因为web标准的贫弱状态以及大量存在的bug,那时web开发特别困难”,《JavaScript: The Good Parts》(以及其他很多JS著作)的作者 Douglas Crockford 说道,“自动升级尚未被引入,所以浏览器新版本的发布并不能消除web上的bug;那只是增加了新的bug”。
尝试在这些浏览器中实现一致的体验就是一场噩梦;而还想动态的实现这些就是噩梦中的噩梦。jQuery 的创建者 John Resig 在谈到该框架的起源时说:
当开始创建这个库的时候,我想解决自己的两个痛点: 1) 提供简单的DOM接口; 2) 减少开发过程中的跨浏览器问题[2]
处理跨多个浏览器的DOM访问是21世纪初web开发者主要面临的问题,但并非他们唯一关心的。业界另一个重磅解决方案就是AJAX,允许和服务器动态交换数据,而非只能依赖于页面渲染时才可获得的数据。Crockford 说:“Jesse James Garrett 在2005年发现了 AJAX -- 一个DHTML的新名字;因为 Netscape 已死以及在 IE6 后微软已经被 web 抛弃,而 W3C 则在徒劳无益的追求语义化 Web,AJAX 取得了远大于 DHTML 的成功。在长期的忽视后,AJAX带来了强烈需要的稳定性。AJAX 是一个巨大的成功,鼓舞了众多库致力于单页 web 应用的开发”。
诸如微软、谷歌和其他大公司等,作为早期的先锋,利用 AJAX 做出了大量激动人心的事情,但直到 2004 年发布的 Gmail,才真正点燃了 web 开发界。完全用全新的方式处理电子邮件:全部事情都在浏览器中进行,并把邮件储存在谷歌的服务器上,这意味着用户可以在世界各地任何支持互联网的设备上访问其邮件,也不用特别安装电子邮件应用程序。虽然不是第一个单页应用,但却是那个时代超然独立的最好应用,整个世界为之侧目。Gmail 用了一种很少被其他网站用到的 DHTML 和类 Ajax 的代码编写方式,并且还做到了其他开发者渴望的快速和易用,这些都导致了包括 jQuery 在内的框架的流行。“jQuery 解决了浏览器兼容性问题、添加了一堆有用的工具,还引入了比 document.getElementById 更好用的选择器”,Nelson 说,“其唯一的问题就是太重了,拨号上网时得下载多于 30kb 的数据”。
在 Crispy Gamer 网站上使用了大量的 jQuery。展开框、头条过渡和切换标签什么的
其实 jQuery 也不是第一个,2005 年 2 月发布的 Prototype 首先被用来为 Ruby on Rails 开发对 AJAX 的支持,同时也支持 DOM 操作 -- 和后来 jQuery 中广为人知的那些差不多。 转年 jQuery 才发布,而 MooTools 发布于 2007 年。这些框架提供了相似的功能,并有各自独特的实现方法。ProtoType 重写和扩展了很多 JS 原生的方法,有些开发者会觉得这样不好。MooTools 更改了 JS 的 Element 对象,也意味着其允许更多的 DOM 操作。
jQuery 并不做以上那些事情,而是聚焦于提供一个以基本的 JS 为基础的框架。短期内这种途径就被证明非常成功,jQuery 成为了主流框架;直到现在依然是,2017 年还是有很多网站还是基于它而非其他的框架开发。
这个框架到底提供了什么呢?先让我们来看看这个纯JS的代码片段,演示了单击元素时隐藏另一个元素的逻辑:
代码语言:javascript复制var el = document.getElementById('myElement');
var el2 = document.getElementById('myOtherElement');
el.addEventListener('click', function (e) {
el2.style.display === 'none';
}
假如你的浏览器支持那些命令,那工作也算完成了,不过当时对于许多 DHTML 和 AJAX 的用例来说这仍是不保险的。用 jQuery 实现相同功能:
代码语言:javascript复制$('#myElement').click(function() {
$('#myOtherElement').hide();
});
并不只是更简明易读了,还带来另外的好处:jQuery确保了其在所有浏览器中都能工作,而工程师就不必花费精力又担惊受怕了。也意味着开发者不必花费同样多的时间造轮子了。当 jQuery 已经提供了 show/hide/toggle 这些函数时,为什么要自己再写一遍呢?“jQuery并未真正改变用JS创建的东西”,Nelson 说,“但是确实改变了如何创建的方式。这使得JS在当时以一种看起来很神奇的方式在运用”。简而言之, jQuery 和类似框架加速并简化了使用者的开发。
...事情发展到某一天。随着网站变得越来越动态化,以及众多公司在缺乏谷歌那种级别的工程师团队的情况下,也以Gmail等为目标开始构建如此复杂的应用,麻烦就接踵而至了。由成千上万行 jQuery 代码组成的大量代码库变得难以维护,又包含了非常多的自定义函数,使得新上手的开发者头疼不已。如果网页上有5个可点击的元素,那就有5个 $('#myElement').click() 的实例要管理;如果有500个可点击的元素呢,麻烦就出现了;如果是5000个元素,可能噩梦就来临了。
需要做更多的事情了。JS框架开始进化,开始呈现明显的类似后端的特性和开发方法。单页应用时代已经到来。
The Single Page App Era - 单页应用时代
时间轴: 约在 2010 - 2014 问题: 不堪重负的 DHTML, 大规模的数据操作, 速度 创新: 类MVC框架, 双向数据流, 智能操作DOM 主要浏览器: Google Chrome, Microsoft IE, Mozilla Firefox, Apple Safari
还有一些其他的创新也促成了单页应用时代的开启。其中一个就是发布于 2008 年的谷歌 Chrome 浏览器。在谷歌的创新中,包含一组前所未见的强劲开发工具。依靠不断的改进和升级,这些工具帮助开发者对 HTML/CSS/JS 实时检视和编辑。还包括了一个智能化的JS调试工具,从而让这门语言的调试接近于传统的编译型语言调试方法(在从前,开发者只能依赖于浏览器插件或外部程序做到这些)。现在大部分主流浏览器都原生提供了类似的能力。
说到谷歌另外的贡献,V8 JavaScript 渲染引擎是其中一个,正是其为 Node.js 这类JS独立运行平台的出现创造了条件。本文主要聚焦于JS前端的历史,但是如果不提及在网站开发中已经成为一种主要因素的 Node.js 的话,那就是我们的失职了。因其快速、异步实现的特征,在开发者中大受欢迎,无论是业余爱好者还是大公司都广泛采用;很多网站都由 Node.js 驱动。
在单页应用时代,并不只是 Chrome,其他浏览器都比其他时期更平等的被使用,这对开发是某种好事。即便是 IE 这样的浏览器,也从善如流的越来越拥抱标准。首次来到了一个有可能无论在哪个浏览器上打开网站,看起来和用起来都一样 -- 顶多有点细微差别的时候。Sass 等 CSS 框架也出现了,这简化了 web 开发的视觉方面;另外对于盒模型的限制也已经被完全整理出来(导致了一系列关于有多少所谓 Web2.0 网站看起来雷同的讨论,有些广为流传,有些鲜为人知)。flexbox即将来临,Ethan Marcotte 在 2010 年发表了他的关于响应式网页设计标志性文章,但过了好长一段时间,该技术看起来才比较稳定了。
在单页应用的世界里,情况没那么复杂了。因为疲于应付成千上万行 jQuery 代码造成的乱局,开发者们开始另寻他法。和上一个时代的框架更关注 DOM 操作以及基本 AJAX 问题不同,新一代的框架被开发出来 -- 为了管理复杂程度日益增长的应用而提供一整套工具。这些 JS 框架多有借鉴,比如 C , PHP, Ruby 等后端语言中已经存在的那些。
2010 年,开发者 Jeremy Ashkenas 向单页应用开发者们发布了 Backbone.js。轻量、快速,并且不依赖于 jQuery (当然开发者们还是可以借助 jQuery 使用更多 Backbone 的特性),Backbone 被用来应对 “jQuery 沼泽”问题。其网站上的这段文字是这样阐释的:
“采用 jQuery 的选择器和回调创建 JS 应用确实简单,但终将陷入一团乱麻;你将手忙脚乱的保持数据在 HTML UI 和 JS 逻辑,以及服务器数据库之间的同步。对富客户端应用来说,更结构化的方式才是更好的”
Backbone 的办法是将代码划分为数据模型类、操作这些数据的函数集合、显示它们的视图类;还提供了一些幕后自动处理的方法。借助于数据和视图的连接,当数据改变需要网站随之更新的时候,开发者就无需过于操心了。Backbone 作为一个卓越的产品,得到了广泛的应用,很多知名 web 应用都由它构建。
同样在 2010 年,AngularJS 的首个版本浮出水面。初始开发者是 Miško Hevery 和 Adam Abrons,并且在 Hevery 被谷歌雇佣后,该项目也落入这家公司之手。经过谷歌和很多奉献于此的外部开发者的持续支持,最近发布的 2.x 版本经过了显著的重写并确实进化了一代。而 1.x 版本仍被谷歌和开发者们支持,并广泛应用于互联网。
用 AngularJS 写成的 To-Do list -- 这个时代中应用界的 “Hello World”
AngularJS 以一种不同于 Backbone.js 的方式提供了一整套前端结构方案。它提供了强有力的工具和一个基于组件的结构,这用 jQuery 是很难或者是不可能搭建起来的。Nelson 说:“数年来我在尝试用 jQuery 和纯 JS 搭建好用的单页应用的过程中屡战屡败,直到我偶然发现了 AngularJS,它教会了我应用模型不用纠结在 DOM 中。这使得大型应用的运转成为可能”。
使用了双向数据流概念的 AngularJS,允许开发者构建同时在服务器端和客户端反映数据变化的应用。举例来说:你可以创建一个 AngularJS 应用,让用户填写表单的时候,实时在页面的其他地方看见正在输入的数据,并且获知这些数据也同步保存到了服务器。切实的改变是,不用为了达成这类同步再写大量 jQuery 代码了。
和 Backbone 类似的是,AngularJS 提供了很多操作 DOM 的辅助工具。同样类似的是,也可以很好的结合 jQuery,但并不需要 jQuery 去承担很多主要功能。这就方便了熟悉 jQuery 生态的开发者逐渐迁移到 AngularJS。
该框架同时也促进了对使用组件的普及 -- 用来呈现 HTML 标签且包含了复杂逻辑的独立函数。这提供了更整洁、划分更清晰的标记;可以像下面这样用标签调用一个组件:
代码语言:javascript复制<userlist ng-repeat="user in $user.list"></userlist>
这段代码生成了一个完整的用户列表,包含丰富的细节,并内嵌了诸如跳转到用户详情页的链接等 HTML。同样重要的是,如果数组 $users.list 中的数据变化了,AngularJS 就会自动根据更新后的新数据自动重新渲染列表,而无需开发者的干预。
有了 Backbone 和 AngularJS,开发者一夜之间就拥有了两个用来开发单页应用的完整工具箱,可以应对之前大规模 jQuery 开发中的短板,并继续用熟悉的方法开发。如果把 JS 比作基本手边工具,而 jQuery 是电动工具的话,那这两个框架就可以说是流水线了 -- 专业集成了为创建单页应用这个特别目的设计的复杂设备。
问题在于...它们都算不上小巧和快速(特别是在移动设备上),这可能会使其难以维护,并且整个双向数据流机制也可能变成一把双刃剑。
Facebook 在 2013 年发布了 React,一个小巧和极速渲染的前端框架。随后其又在 2014 年发布了其基于事件的应用管理和开发工具 Flux。这些产品以及围绕其成长的相关技术,再一次改变了 JS 应用开发。
The Modern Era - 现代时代
时间轴: 约从 2014 至今 问题: 速度, 增长的应用复杂性, 可靠性 创新: Virtual DOM, 单向数据流, 强类型, 测试 主要浏览器: Google Chrome, Apple Safari
在过去的几年,网页的访问方式发生了深刻的变化。曾经是家用 PC 独占的网站访问领域,现在变成了手机、平板电脑、笔记本电脑,以及台式机并存的情况。这些设备的带宽、处理器能力以及可用的屏幕分辨率各有不同。少量下载和快速渲染变得特别实用...你所熟悉的用大量图片下载、几兆几兆的广告代码、自动播放的视频等来打动用户的作法已经过时!
和用户的期待不同的是,很多内容网站还不是单页应用。单页应用被用来替代原生应用,在速度和响应能力方面也被寄予和原生应用同样的期望。用户也许能忍受用 5 秒钟加载一条最新的体育新闻,但很难做到花同样的时间在银行应用程序或分析监控面板里去等待点击按钮后的响应。
Facebook 为其开发者们发布了 React,以便迅速易用的进行开发。很多人的努力和智慧凝聚其中。它并非完美,还有更新更好的后来者层出不穷,且虽然它为开发者提供了很多东西 -- 而其中很多用到的东西其实并不是项目中真正需要的...但我们仍会从中获益。
React 并不是作为 JS 框架替代 Backbone 和 AngularJS 的,虽然确实削弱了它们;部分原因是 React 并不是一个完整的框架。React 初期主要被构想成一个 MVC 框架中的视图层语言。尽管很多其他自定义技术也是由 Facebook 开发的,但它确实可以结合各种既有技术;换句话说,对非 Facebook 的技术一视同仁,React 不处理数据、不处理事件、不处理 XHR/AJAX ... 所做的就是渲染组件。
在阅读本文时,很可能你已经听说或正在使用 React 作为整个前端的解决方案了。为什么会这样?因为借助 Webpack 或 Browserify 等打包技术,整个生态围绕 React 生长,使得 "React" 实际上是 "React 加上一整套的其他东西" 的简称。Nelson 简短的总结为:“在某种程度上,会感觉所谓现代时代很像 jQuery 时代,构建单页应用轻而易举,从而没必要去搞新类型的应用。React 用更简单的方法创建可重用组件;Webpack 和 NPM 促进了那些组件和其价值的分享;而 Babel 意味着我们不用创建新语言,用 JS 就好了”。
不管怎样,React 也还是存在其问题。基于打包的生态意味着如果不付出很多努力,JS 文件尺寸将迅速失控。即便对于资深开发者,要掌控全局也不那么容易,更甭提新手了。高质量的文档和友好的社区会缓和这些问题,但学习曲线依旧陡峭。
其他框架也雨后春笋般的出现。AngularJS 2 借鉴了很多类似 React 的方式大幅重写了其功能;其渲染速度大大优于版本 1,尤其在显示大量数据时。早于 React 至少一年发布的 Meteor (事实上,也可以用 React 作为其视图层), 也有自己的拥趸。最早在 2014 年发布的 Vue.js,是一个小巧快速的前端框架,能很好的结合其他技术;其语法类似 React,其结构也是类似的基于组件的实现,虽然不是一模一样吧。Preact 也是一个极小而快速的 React 替代品,它基于日益普遍使用的 ES6 -- 一个日益广受欢迎的更现代化 JS 版本(React 一开始用差不多已经被熟知了十年左右的 ES5 构建,也可以用 ES6 工作)。此外还有一些其他框架。
需要特别关注的是 React、AngularJS 等所做的事情,并不是在重复造轮子。“没人再提 DHTML 或 AJAX 了,人们都开始说单页应用,但其实是新瓶装旧酒” -- 这很大程度上是对的;基础代码仍是 JS,也仍旧干着早期的事情。不同一点的是今天的实现途径。
所有这些框架都倾向于解决相同的问题:创建很多工具方便开发者快速构建,以使单页 web 应用能很好的工作于多种设备上。它们很注重数据流和显示:基本上,对于取得终端用户所需的显示数据,并在数据变化时自动更新显示这部分工作,减轻了开发者必须的工作量。当处理海量数据,并且想给用户提供类似应用的体验时,这些框架真的是能救命啊。
下面说说 Vanilla JS。当前,你可能想知道如果某人在开发一个只需不多 JS 的小网站改用什么呢。AngularJS 和 React 看起来都是杀鸡用牛刀,是吧?
确实是。当你只想监听几个按钮以及切换 tab 的时候,用大量现代 JS 框架组成的好得很的单页应用就过于复杂了。"我该用什么?"的答案就是:取决于具体的需求,用 jQuery 或 Vanilla JS 都可以。
Vanilla JS 可不是一个框架,也不是一个库,其实什么也不是,就是 JavaScript。最近的更新已经使 JS 相当易用了。比如document.querySelector
和document.querySelectorAll
,用类似 CSS 的语法提供了类 jQuery 的元素选择(比如 ".exterior-link")。ES5, ES6, 和 ES7 基本上已经被现代浏览器所支持;老旧浏览器正迅速减少,对于那些不在受制于此的用户,就降低了借助 jQuery 跨浏览器的需要。从性能考虑,书写纯 JS 代码几乎肯定会更快(除非你的程序不优化),即便是在更老更慢的设备上。和很多开发者一样,Smith 对这种新关注点很兴奋:“我从 Vanilla JS 获得了很多回报。我已经彻底厌烦了 Stack Overflow 那些滥用 jQuery 和其他框架的家伙。引入 jQuery 就是为了把原本 3 行代码能解决的问题写成 5 行吗?”
所以,在当今,2017年,JS 生态系统繁荣而混乱。没人能预测前方的情况,持续生长的只有变化。web 裹足不前也就意味着 JS 的止步,我们也很期待未来时代能带来什么。希望你能觉得本文有趣又有益,并且更加留意我们在何处、我们如何来到此地,以及为什么我们选择了这条路。感谢阅读。