2757com 12

这个阶段涌现出了很多关注点相对集中、设计理念更为优秀的框架2757com,前端迷思与React.js

我的前端之路:工具化与工程化

2017/01/07 · 基础技术 ·
工具化,
工程化

原文出处:
王下邀月熊_Chevalier   

2757com 1

前言

近年来,随着浏览器性能的提升与移动互联网浪潮的汹涌而来,Web前端开发进入了高歌猛进,日新月异的时代。这是最好的时代,我们永远在前行,这也是最坏的时代,无数的前端开发框架、技术体系争妍斗艳,让开发者们陷入困惑,乃至于无所适从。

Web前端开发可以追溯于1991年蒂姆·伯纳斯-李公开提及HTML描述,而后1999年W3C发布HTML4标准,这个阶段主要是BS架构,没有所谓的前端开发概念,网页只不过是后端工程师的顺手之作,服务端渲染是主要的数据传递方式。接下来的几年间随着互联网的发展与REST等架构标准的提出,前后端分离与富客户端的概念日渐为人认同,我们需要在语言与基础的API上进行扩充,这个阶段出现了以jQuery为代表的一系列前端辅助工具。2009年以来,智能手机开发普及,移动端大浪潮势不可挡,SPA单页应用的设计理念也大行其道,相关联的前端模块化、组件化、响应式开发、混合式开发等等技术需求甚为迫切。这个阶段催生了Angular
1、Ionic等一系列优秀的框架以及AMD、CMD、UMD与RequireJS、SeaJS等模块标准与加载工具,前端工程师也成为了专门的开发领域,拥有独立于后端的技术体系与架构模式。

而近两年间随着Web应用复杂度的提升、团队人员的扩充、用户对于页面交互友好与性能优化的需求,我们需要更加优秀灵活的开发框架来协助我们更好的完成前端开发。这个阶段涌现出了很多关注点相对集中、设计理念更为优秀的框架,譬如
ReactVueJSAngular2
等组件框架允许我们以声明式编程来替代以DOM操作为核心的命令式编程,加快了组件的开发速度,并且增强了组件的可复用性与可组合性。而遵循函数式编程的
Redux 与借鉴了响应式编程理念的 MobX
都是非常不错的状态管理辅助框架,辅助开发者将业务逻辑与视图渲染剥离,更为合理地划分项目结构,更好地贯彻单一职责原则与提升代码的可维护性。在项目构建工具上,以
GruntGulp 为代表的任务运行管理与以 WebpackRollup
JSPM
为代表的项目打包工具各领风骚,帮助开发者更好的搭建前端构建流程,自动化地进行预处理、异步加载、Polyfill、压缩等操作。而以NPM/Yarn为代表的依赖管理工具一直以来保证了代码发布与共享的便捷,为前端社区的繁荣奠定了重要基石。

前端迷思与React.js

本文转自本人的知乎文章,做了些许简化修改
原文链接

我的前端之路

2016/07/18 · 前端职场 · 4
评论 ·
职场

原文出处: 王下邀月熊   

笔者的Web前端开发文章索引目录

撰写本文的时候笔者阅读了以下文章,不可避免的会借鉴或者引用其中的一些观点与文字,若有冒犯,请随时告知。文列如下:

  • RePractise前端篇:
    前端演进史
  • 前端的变革
  • 致我们终将组件化的Web
  • 我感觉到的前端变化
  • 解读2015之前端篇:工业时代
    野蛮发展
  • 前端工程化知识要点回顾&思考
  • Thoughts about React, Redux & javascript in
    2016

如果你想进行WebAPP的学习,建议先看下我的编程之路:知识管理与知识体系相关内容
顺便推广下笔者总结的泛前端知识点纲要总结:Coder
Essential之客户端知识索引(iOS/Android/Web)、Coder
Essential之编程语言学习知识点纲要、Coder
Essential之编程语言语法特性概论

几年前初入大学,才识编程的时候,崇尚的是一路向下,那个时候喜欢搞Windows、Linux底层相关的东西,觉得那些做网页的太Low了。直到后来偶然的机会接触到HTML、JavaScript、CSS,很长一段时间觉得这种这么不严谨的,毫无工程美学的搭配不过是诗余罢了。后来,深入了,才发现,能够有幸在这片星辰大海里游荡,可以以几乎领先于其他方向的技术变革速度来感受这个时代的脉动,是多么幸运的一件事。这是一个最坏的时代,因为一不小心就发现自己Out了;这也是一个最好的时代,我们永远在前行。繁华渐欲,万马齐鸣!

借用苏宁前端结构师的总结,任何一个编程生态都会经历三个阶段,第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。当然,笔者以Tools-Frameworks-Library只是想说明我个人感觉的变化。

笔者从jQuery时代一路走来,经历了以BootStrap为代表的基于jQuery的插件式框架与CSS框架的兴起,到后面以Angular
1为代表的MVVM框架,以及到现在以React为代表的组件式框架的兴起。从最初的认为前端就是切页面,加上一些交互特效,到后面形成一个完整的webapp,总体的变革上,笔者以为有以下几点:

  • 移动优先与响应式开发
  • 前端组件化与工程化的变革
  • 从直接操作Dom节点转向以状态/数据流为中心

笔者在本文中的叙事方式是按照自己的认知过程,夹杂了大量个人主观的感受,看看就好,不一定要当真,毕竟我菜。梳理来说,有以下几条线:

  • 交互角度的从PC端为中心到Mobile First
  • 架构角度的从以DOM为中心到MVVM/MVP到以数据/状态为驱动。
  • 工程角度的从随意化到模块化到组件化。
  • 工具角度的从人工到Grunt/Gulp到Webpack/Browserify。

在正文之前,重要的事情说三遍,我是菜鸟!我是菜鸟!我是菜鸟!从来都没有最好的技术,而只有合适的技术与懂它的人。我感谢这些伟大的类库/框架,感恩它们的Contributor,给我呈现了一个何其广阔的世界。虽然2015的前端领域有点野蛮生长,但是也体现了前端一直是开源领域的扛鼎之处,希望有一天我也能为它的繁荣做出自己的贡献。

前言

纷扰

分久必合,合久必分啊,无论是前端开发中各个模块的分割还是所谓的前后端分离,都不能形式化的单纯按照语言或者模块来划分,还是需要兼顾功能,合理划分。

任何一个编程生态都会经历三个阶段:

  • 第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。
  • 第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。
  • 第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。

本文的主旨希望能够尽可能地脱离工具的束缚,回归到前端工程化的本身,回归到语言的本身,无论React、AngularJS、VueJS,它们更多的意义是辅助开发,为不同的项目选择合适的工具,而不是执念于工具本身。总结而言,目前前端工具化已经进入到了非常繁荣的时代,随之而来很多前端开发者也甚为苦恼,疲于学习。工具的变革会非常迅速,很多优秀的工具可能都只是历史长河中的一朵浪花,而蕴藏其中的工程化思维则会恒久长存。无论你现在使用的是React还是Vue还是Angular
2或者其他优秀的框架,都不应该妨碍我们去了解尝试其他。

    前端技术这几年蓬勃发展, 这是当时某几个项目需要做前端技术选型时,
相关资料整理, 部分评论引用自社区。

2016年弹指一挥间,转眼间已到了自己学习web的第三个年头。在过去的这一年,前端领域发生了翻天覆地的变化——

基石与催化剂

二十载光辉岁月

2757com 2

近年来,随着浏览器性能的提升与移动互联网浪潮的汹涌而来,Web前端开发进入了高歌猛进,日新月异的时代。这是最好的时代,我们永远在前行,这也是最坏的时代,无数的前端开发框架、技术体系争妍斗艳,让开发者们陷入困惑,乃至于无所适从。Web前端开发可以追溯于1991年蒂姆·伯纳斯-李公开提及HTML描述,而后1999年W3C发布HTML4标准,这个阶段主要是BS架构,没有所谓的前端开发概念,网页只不过是后端工程师的顺手之作,服务端渲染是主要的数据传递方式。接下来的几年间随着互联网的发展与REST等架构标准的提出,前后端分离与富客户端的概念日渐为人认同,我们需要在语言与基础的API上进行扩充,这个阶段出现了以jQuery为代表的一系列前端辅助工具。2009年以来,智能手机开发普及,移动端大浪潮势不可挡,SPA单页应用的设计理念也大行其道,相关联的前端模块化、组件化、响应式开发、混合式开发等等技术需求甚为迫切。这个阶段催生了Angular
1、Ionic等一系列优秀的框架以及AMD、CMD、UMD与RequireJS、SeaJS等模块标准与加载工具,前端工程师也成为了专门的开发领域,拥有独立于后端的技术体系与架构模式。而近两年间随着Web应用复杂度的提升、团队人员的扩充、用户对于页面交互友好与性能优化的需求,我们需要更加优秀灵活的开发框架来协助我们更好的完成前端开发。这个阶段涌现出了很多关注点相对集中、设计理念更为优秀的框架,譬如React、VueJS、Angular
2等组件框架允许我们以声明式编程来替代以DOM操作为核心的命令式编程,加快了组件的开发速度,并且增强了组件的可复用性与可组合性。而遵循函数式编程的Redux与借鉴了响应式编程理念的MobX都是非常不错的状态管理辅助框架,辅助开发者将业务逻辑与视图渲染剥离,更为合理地划分项目结构,更好地贯彻单一职责原则与提升代码的可维护性。在项目构建工具上,以Grunt、Gulp为代表的任务运行管理与以Webpack、Rollup、JSPM为代表的项目打包工具各领风骚,帮助开发者更好的搭建前端构建流程,自动化地进行预处理、异步加载、Polyfill、压缩等操作。而以NPM/Yarn为代表的依赖管理工具一直以来保证了代码发布与共享的便捷,为前端社区的繁荣奠定了重要基石。

工具化

我们学习的速度已经跟不上新框架新概念涌现的速度,用于学习上的成本远大于实际开发项目的成本。我们不一定要去用最新最优秀的工具,但是我们有了更多的选择余地,相信这一点对于大部分非处女座人士而言都是喜讯。

工具化是有意义的。工具的存在是为了帮助我们应对复杂度,在技术选型的时候我们面临的抽象问题就是应用的复杂度与所使用的工具复杂度的对比。工具的复杂度是可以理解为是我们为了处理问题内在复杂度所做的投资。为什么叫投资?那是因为如果投的太少,就起不到规模的效应,不会有合理的回报。这就像创业公司拿风投,投多少是很重要的问题。如果要解决的问题本身是非常复杂的,那么你用一个过于简陋的工具应付它,就会遇到工具太弱而使得生产力受影响的问题。反之,是如果所要解决的问题并不复杂,但你却用了很复杂的框架,那么就相当于杀鸡用牛刀,会遇到工具复杂度所带来的副作用,不仅会失去工具本身所带来优势,还会增加各种问题,例如培训成本、上手成本,以及实际开发效率等。

所谓GUI应用程序架构,就是对于富客户端的代码组织/职责划分。纵览这十年内的架构模式变迁,大概可以分为MV与Unidirectional两大类,而Clean
Architecture则是以严格的层次划分独辟蹊径。从MVC到MVP的变迁完成了对于View与Model的解耦合,改进了职责分配与可测试性。而从MVP到MVVM,添加了View与ViewModel之间的数据绑定,使得View完全的无状态化。最后,整个从MV
到Unidirectional的变迁即是采用了消息队列式的数据流驱动的架构,并且以Redux为代表的方案将原本MV*中碎片化的状态管理变为了统一的状态管理,保证了状态的有序性与可回溯性。
具体到前端的衍化中,在Angular
1兴起的时代实际上就已经开始了从直接操作Dom节点转向以状态/数据流为中心的变化,jQuery
代表着传统的以 DOM 为中心的开发模式,但现在复杂页面开发流行的是以 React
为代表的以数据/状态为中心的开发模式。应用复杂后,直接操作 DOM
意味着手动维护状态,当状态复杂后,变得不可控。React
以状态为中心,自动帮我们渲染出 DOM,同时通过高效的 DOM Diff
算法,也能保证性能。

2757com 3
开始吧:

  • Angular1.x慢慢退出舞台,Angular2、React、Vue等新兴的MVVM框架已接近成熟。经过一年的迭代,API与底层设计思路上有趋同之势,但也慢慢显现出在各自领域中的优势。
  • 以Redux和Vuex为代表的类Flux设计架构,经过一年的探索和实践,其在开发效率和维护追踪上的优势已被验证,取代MVC成为了中大型web应用中最流行的框架模式。
  • Webpack、Rollup等包管理工具已是工程必备,ES6和Babel普及度已经很高了,前端开发完成从页面到组件化模块化、从解释型到构建型的工程性转变。
    写这篇文章的初衷,一是由于这一年中也大大小小做过好几个项目,对于前端工程有一些浅薄的理解和经验,想要成文记录下来;二是结合已有的知识,畅想一下未来web发展的趋势。

浏览器的跃进

现在H5已经成为了一个符号,基本上所有具有绚丽界面或者交互的Web界面,无论是PC还是Mobile端,都被称为基于H5。笔者一直认为,H5技术的发展以及带来的一系列前端的变革,都离不开现代浏览器的发展与以IE为典型代表的老的浏览器的消逝。目前浏览器的市场分布可以由如下两个图:

  • 浏览器分布图
    2757com 4
  • 国际浏览器分布图
    2757com 5

这里顺嘴说下,如果想要明确某个属性是否可以使用可以参考Can I
Use。话说虽然微信内置的某X5内核浏览器连Flexbox都不支持,不过它帮我们屏蔽了大量手机的底层差异,笔者还是非常感恩的。当然了,在有了Webpack之后,用Flexbox不是问题,可以查看这嘎达。

纷扰之虹

笔者在前两天看到了Thomas
Fuchs的一则Twitter,也在Reddit等社区引发了热烈的讨论:我们用了15年的时间来分割HTML、JS与CSS,然而一夕之间事务仿佛回到了原点。
2757com 6分久必合,合久必分啊,无论是前端开发中各个模块的分割还是所谓的前后端分离,都不能形式化的单纯按照语言或者模块来划分,还是需要兼顾功能,合理划分。笔者在2015-我的前端之路:数据流驱动的界面中对自己2015的前端感受总结中提到过,任何一个编程生态都会经历三个阶段,第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。在2016的上半年中,笔者在以React的技术栈中挣扎,也试用过VueJS与Angular等其他优秀的前端框架。在这一场从直接操作DOM节点的命令式开发模式到以状态/数据流为中心的开发模式的工具化变革中,笔者甚感疲惫。在2016的下半年中,笔者不断反思是否有必要使用React/Redux/Webpack/VueJS/Angular,是否有必要去不断追逐各种刷新Benchmark
记录的新框架?本文定名为工具化与工程化,即是代表了本文的主旨,希望能够尽可能地脱离工具的束缚,回归到前端工程化的本身,回归到语言的本身,无论React、AngularJS、VueJS,它们更多的意义是辅助开发,为不同的项目选择合适的工具,而不是执念于工具本身。

总结而言,目前前端工具化已经进入到了非常繁荣的时代,随之而来很多前端开发者也甚为苦恼,疲于学习。工具的变革会非常迅速,很多优秀的工具可能都只是历史长河中的一朵浪花,而蕴藏其中的工程化思维则会恒久长存。无论你现在使用的是React还是Vue还是Angular
2或者其他优秀的框架,都不应该妨碍我们去了解尝试其他,笔者在学习Vue的过程中感觉反而加深了自己对于React的理解,加深了对现代Web框架设计思想的理解,也为自己在未来的工作中更自由灵活因地制宜的选择脚手架开阔了视野。

引言的最后,我还想提及一个词,算是今年我在前端领域看到的出镜率最高的一个单词:Tradeoff(妥协)。

工具化的不足:抽象漏洞定理

抽象漏洞定理是Joel在2002年提出的,所有不证自明的抽象都是有漏洞的。抽象泄漏是指任何试图减少或隐藏复杂性的抽象,其实并不能完全屏蔽细节,试图被隐藏的复杂细节总是可能会泄漏出来。抽象漏洞法则说明:任何时候一个可以提高效率的抽象工具,虽然节约了我们工作的时间,但是,节约不了我们的学习时间。我们在上一章节讨论过工具化的引入实际上以承受工具复杂度为代价消弭内在复杂度,而工具化滥用的结局即是工具复杂度与内在复杂度的失衡。

谈到这里我们就会明白,不同的项目具备不同的内在复杂度,一刀切的方式评论工具的好坏与适用简直耍流氓,而且我们不能忽略项目开发人员的素质、客户或者产品经理的素质对于项目内在复杂度的影响。对于典型的小型活动页,譬如某个微信H5宣传页,往往注重于交互动画与加载速度,逻辑复杂度相对较低,此时Vue这样渐进式的复杂度较低的库就大显身手。而对于复杂的Web应用,特别是需要考虑多端适配的Web应用,尽量使用React这样相对规范严格的库。

  • 目前, Web 开发技术框架选型为两种的占 80% 。这种戏剧性的变化持续了近
    6 年。
  • 自 2013 年 5
    月推出以来,ReactJS
    在过去三年中已成为了 Web 开发领域的中坚力量。

关于Flux的经验思考

何为Flux不再过多赘述,不懂的读者推荐这篇文章图解Flux。

2757com 7

Flux架构概念图

说白了,Flux就是一种新的单向数据流的“视图绑定式”解决方案。这里我个人加了“视图绑定式”这个定义,是因为只有在View-Model绑定的基础上,Flux才能充分发挥它的作用。
上图是Flux的架构图。简单地说,Flux将视图变成了状态机,所有对视图的操作都转变为对Store的状态操作。状态的更新会通过各种框架的映射机制反应到视图上。而在具体的实现中(Redux,Vuex),Store往往被设置成全局的单一状态树。这样一来,各组件、各模块之间将不存在任何数据交互关系,完全解耦。所有的模块或组件只做三件事:接收用户在视图层的指令,更改全局Store树,从Store中获取各组件的状态。
由于没有基于Redux做过工程方面的实践,所以这里重点说一下Vuex,不知道Vuex的同学可以戳这里Vuex。(这里要特别安利Vue.js这款非常棒的渐进式框架,本身很轻,适合小型应用的开发,同时又有构建大型应用的解决方案)

2757com 8

Vuex架构图

个人认为,利用Vuex,与传统的MVVM架构相比,对于构建中大型项目有如下优势——

  • 很好地解决了父子组件数据级联与组件间的通讯问题。在传统的MVVM模式下,我们通常采用事件机制进行跨组件的数据传输,这种做法的一大坏处就在于组件之间产生耦合。在中大型规模的项目中,常常有上百甚至上千的组件(像这学期的学雷锋项目教学辅助应用,算是中小型规模,就已经有将近50个组件),组件间的交互将变得极其复杂和难以追踪,导致开发和维护成本非常高。而在Flux,确认地说是Vuex中,组件的所有动作都是发送事件,调用全局的action(action本质上是订阅的回调函数)。同时,组件的状态也是由全局的state树派生出来,并与其绑定。如此,所有组件对视图的更改,都转变为对全局状态的更改,从而避免了组件间的通讯。
  • 方便追踪应用数据流。前面我们提到,级联的跨组件通讯带来了很强的耦合性,不仅如此,还使得数据流难以追踪。在使用MVC架构的中大型规模web项目中,前端往往一次性要存储和展示几十甚至上百种数据,牵扯到好几种Model,并且这些Model之间一定是“纠缠不清”的。这时候一旦出现Bug,很难去进行Bug定位。而Vuex中数据流是单向的,事情就简单很多——首先,定位出现Bug的相关视图和操作;然后,根据视图分析出相关State->Mutations->Actions(过程和数据流方向是相反的);最后,通过Actions和视图操作找到出问题的组件。(如果你严格按照模块化或组件化的模式来组织代码,那Debug效率又会提升很多。)
  • 方便预测和回溯应用状态。前面也提到,Flux架构下的应用实际是一个状态机,而整个数据流是单向的,因此我们很容易根据一个Action便预测出应用下一阶段的状态。同时,在做“撤回”、“重做”等类似回溯的功能时,也可以很轻易地通过保存和提取应用在某一阶段的状态来实现。另外,Vuex中的Mutations专门用于更改State,官方建议是同步操作放在Mutations(参考这篇答案),这样的好处是每当调用Mutations便可同步获得一个新的应用状态,方便做snapshot。

但任何框架或架构的引入,都必须基于对于项目类型和项目规模的考量之上。Flux尤擅于数据类型繁多,交互密集的应用,但对于数据类型较少、交互不多的应用(例如H5,展示型网站等),就不适用了。

另外,尽管是在中大型项目中,严格遵循Flux有时也会把一些问题复杂化,例如下面的.vue模板代码:

<template>
  <div> 
    <v-loading v-if="isLoading"></v-loading> //一个loading动画
  </div>
</template>
<script> 
  import {mapState} from "vuex"; 
  export default { 
      data(){
         return{ 
            isLoading:false //局部state的形式 
         }
    }, 
    computed:mapState(state){ //引入全局state的形式
         isLoading:state=>state.isLoading 
    }, 
    methods:{
       someFunction(){
           isLoading=true; //第一种方式
           //this.$store.dispatch('isloading',true) //第二种方式
           ... 
        } 
    } 
}
</script>

上段代码中使用了两种引入state的模式,一种是组件自身的局部state,由data进行初始化;另一种是严格遵守Flux,从全局Store中提取的state。如果我们使用第二种方式更改一个动画loading,那我们需要专门像下面的代码一样编写actions,mutations:

export const loading=({commit},signal)=>{ 
    commit('loading',signal);
}

const state={
    isLoading:false; //loading的全局state状态
}
const mutations={
    loading(state,signal){ 
        state.isLoading=signal; //更改state 
    }
}

当loading比较多的时候,会显得很麻烦。而如果采用局部state的方式,我们只需要在methods中更改状态即可。但问题在于,actions中常常有异步事件(如AJAX),需要在异步完成后调整loading的状态,根据单向数据流的原则,看上去只能通过修改全局的state来达到目的。

ES6提供了一个非常好的工具——Promise。具体请参照Vuex文档。如此我们便可以做到类似如下的调用:

 ...
}, 
methods:{ 
    someFunction(){ 
        this.$store.dispatch('loading',true).then( 
        ()=>{ //成功回调 
            isLoading=true; 
        }, 
        ()=>{} //失败回调 
        ) 
    } 
}}

如此一来便能在Vuex的架构下充分利用局部State管理视图,不仅可以提高开发效率,也有利于保持全局State的简洁。

ECMAScript

2015年是JavaScript诞生的20周年。同时又是ES6标准落地的一年。ES6是迄今为止
ECMAScript标准最大的变革(如果不算上胎死腹中的ES4的话),带来了一系列令开发者兴奋的新特性。从目前es的进化速度来看,es后面应该会变成一个个的feature发布而不是像以前那样大版本号的方式,所以现在官方也在推荐
ES+年份这种叫法而不是
ES+版本。在ES2015中,笔者觉得比较欣赏的特性如下,其他完整的特性介绍可以参考这篇文章ES6
Overview in 350 Bullet Points。

  • Module & Module
    Loader:ES2015中加入的原生模块机制支持可谓是意义最重大的feature了,且不说目前市面上五花八门的module/loader库,各种不同实现机制互不兼容也就罢了(其实这也是非常大的问题),关键是那些模块定义/装载语法都丑到爆炸,但是这也是无奈之举,在没有语言级别的支持下,js只能做到这一步,正所谓巧妇难为无米之炊。ES2016中的Module机制借鉴自
    CommonJS,同时又提供了更优雅的关键字及语法(虽然也存在一些问题)。
  • Class:准确来说class关键字只是一个js里构造函数的语法糖而已,跟直接function写法无本质区别。只不过有了Class的原生支持后,js的面向对象机制有了更多的可能性,比如衍生的extends关键字(虽然也只是语法糖)。
  • Promise & Reflect
    API:Promise的诞生其实已经有几十年了,它被纳入ES规范最大意义在于,它将市面上各种异步实现库的最佳实践都标准化了。至于Reflect
    API,它让js历史上第一次具备了元编程能力,这一特性足以让开发者们脑洞大开。

除此之外,ES2016的相关草案也已经确定了一大部分其他new
features。这里提两个我比较感兴趣的new feature:

  • async/await:协程。ES2016中 async/await
    实际是对Generator&Promise的上层封装,几乎同步的写法写异步比Promise更优雅更简单,非常值得期待。
  • decorator:装饰器,其实等同于Java里面的注解。注解机制对于大型应用的开发的作用想必不用我过多赘述了。用过的同学都说好。

更让人兴奋的是,JavaScript慢慢不再局限于前端开发中,NodeJs的提出让人们感受到了利用JavaScript进行全栈开发的能力,从此大大提高了开发的效率(至少不用多学习一门语言)。JavaScript在物联网中的应用也曾经引起一些追捧与风潮,不过今年物联网社区更加冷静地看待着这个问题,但是并不影响各大厂商对于JavaScript的支持,可以参阅javascript-beyond-the-web-in-2015这篇文章。笔者还是很看好JavaScript在其他领域继续大放异彩,毕竟ECMAScript
6,7已经是如此的优秀。

工具化

2757com 9

月盈而亏,过犹不及。相信很多人都看过了2016年里做前端是怎样一种体验这篇文章,2016年的前端真是让人感觉从入门到放弃,我们学习的速度已经跟不上新框架新概念涌现的速度,用于学习上的成本远大于实际开发项目的成本。不过笔者对于工具化的浪潮还是非常欢迎的,我们不一定要去用最新最优秀的工具,但是我们有了更多的选择余地,相信这一点对于大部分非处女座人士而言都是喜讯。年末还有一篇曹刘阳:2016年前端技术观察也引发了大家的热议,老实说笔者个人对文中观点认同度一半对一半,不想吹也不想黑。不过笔者看到这篇文章的第一感觉当属作者肯定是大公司出来的。文中提及的很多因为技术负债引发的技术选型的考虑、能够拥有相对充分完备的人力去进行某个项目,这些特征往往是中小创公司所不会具备的。

React?Vue?Angular 2?

React,Vue,Angular
2都是非常优秀的库与框架,它们在不同的应用场景下各自具有其优势。Vue最大的优势在于其渐进式的思想与更为友好的学习曲线,Angular
2最大的优势其兼容并包形成了完整的开箱即用的All-in-one框架,而这两点优势在某些情况下反而也是其劣势,也是部分人选用React的理由。很多对于技术选型的争论乃至于谩骂,不一定是工具的问题,而是工具的使用者并不能正确认识自己或者换位思考他人所处的应用场景,最终吵的驴唇不对马嘴。

任何组件与框架都有它的适用场景, 我们应该冷静分析与权衡, 先来看React.js

框架与工具的思考

尤大在文章”Vue2.0
渐进式前端解决方案”里对工具框架引入的考量作了非常恰当的比喻。

工具复杂度是为了处理内在复杂度所做的投资。为什么叫投资?那是因为如果投的太少,就起不到规模的效应,不会有合理的回报。这就像创业公司拿风投,投多少是很重要的问题。如果要解决的问题本身是非常复杂的,那么你用一个过于简陋的工具应付它,就会遇到工具太弱而使得生产力受影响的问题。

这里的复杂度,我认为是针对特定团队而言的。比如你的团队对React全家桶有丰富的实践经验,那么在为相同的项目选型时,React的复杂度于你的团队和于其他团队是不同的。但这么看其实是很虚的,原因是很少有人能准确地评估应用内在复杂度和工具复杂度。

经过观察,通常情况是高估内在复杂度,低估工具复杂度。所以现阶段我总结了一条不是很正确,但起码不会错的方法论:以最佳实践为基础,再增量考察和评估额外的工具引入成本

举两个栗子:

  1. 对于非常轻的页面,如H5、活动页面,最佳实践一般是Jquery或zepto+UI库。但现在很多轻页面开始有一些数据交互的需求,需要考虑引入一些MVVM框架,这时候再增量评估引入React、Vue这些View层框架的复杂度及应用内在复杂度,而不是把Jquery或Zepto和它们放到同一地位来进行比较考量。
  2. 开发单页面应用,一般来说是以数据交互为主的需求。Vue全家桶的最佳实践是Webpack+Vue(单文件组件解决方案)+Vue-router。React全家桶的最佳实践是Webpack+React+React-router。以此为基准,综合项目预期成本,再考虑加入UI库、Babel、Redux(Vuex)带来的额外复杂度和消弭应用内在复杂度之间的平衡关系。

这样的好处是基本跳过最佳实践的复杂度评估,直接对风险较高、把握较低的复杂度部分进行评估,节省了决策成本,原因有二:

  1. 一般来说,最佳实践是在各种工具的组合下,复杂度最低的方案。
  2. 最佳实践本身包含了前人的决策经验和教训,没有必要花过多时间来做重复地评估决策。

另外,以上所说的“最佳实践”,有两点需要注意的地方:

  1. 重点不是在best,而是在experience。不要陷入了找寻最优解的泥潭。
  2. “最佳”不是绝对概念,而是相对概念。一定要针对个人(团队)的情况来考虑何为“最佳”。

WebAssembly

WebAssembly
选择了跟ES2015在同一天发布,其项目领头人是大名鼎鼎的js之父Brendan
Eich。WebAssembly旨在解决js作为解释性语言的先天性能缺陷,试图通过在浏览器底层加入编译机制从而提高js性能。WebAssembly所做的正是为Web打造一套专用的字节码,这项标准在未来应用场景可能是这样的:

  1. 开发应用,但使用任何一门可被编译为WebAssembly的语言编写源代码。
  2. 用编译器将源代码转换为WebAssembly字节码,也可按需转换为汇编代码。
  3. 在浏览器中加载字节码并运行。

2757com 10

需要注意的是,WebAssembly不会替代JavaScript。越来越多的语言和平台想在Web上大展手脚,这会迫使JavaScript和浏览器厂商不得不加快步伐来补充缺失的功能,其中某些功能通过复杂的JavaScript语义来实现并不合适,所以WebAssembly可以作为JavaScript的补集加入到Web阵营中来。WebAssembly最一开始的设计初衷就是作为不依赖于JavaScript的编译目标而存在,进而获得了主流浏览器厂商的广泛支持。很期待有一天WebAssembly能够发展起来,到那个时候,我们用JavaScript编写的应用也会像现在用汇编语言写出的大型程序的感觉咯~

工具化的意义

工具化是有意义的。笔者在这里非常赞同尤雨溪:Vue
2.0,渐进式前端解决方案的思想,工具的存在是为了帮助我们应对复杂度,在技术选型的时候我们面临的抽象问题就是应用的复杂度与所使用的工具复杂度的对比。工具的复杂度是可以理解为是我们为了处理问题内在复杂度所做的投资。为什么叫投资?那是因为如果投的太少,就起不到规模的效应,不会有合理的回报。这就像创业公司拿风投,投多少是很重要的问题。如果要解决的问题本身是非常复杂的,那么你用一个过于简陋的工具应付它,就会遇到工具太弱而使得生产力受影响的问题。反之,是如果所要解决的问题并不复杂,但你却用了很复杂的框架,那么就相当于杀鸡用牛刀,会遇到工具复杂度所带来的副作用,不仅会失去工具本身所带来优势,还会增加各种问题,例如培训成本、上手成本,以及实际开发效率等。

2757com 11

笔者在GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean一文中谈到,所谓GUI应用程序架构,就是对于富客户端的代码组织/职责划分。纵览这十年内的架构模式变迁,大概可以分为MV*与Unidirectional两大类,而Clean
Architecture则是以严格的层次划分独辟蹊径。从笔者的认知来看,从MVC到MVP的变迁完成了对于View与Model的解耦合,改进了职责分配与可测试性。而从MVP到MVVM,添加了View与ViewModel之间的数据绑定,使得View完全的无状态化。最后,整个从MV*到Unidirectional的变迁即是采用了消息队列式的数据流驱动的架构,并且以Redux为代表的方案将原本MV*中碎片化的状态管理变为了统一的状态管理,保证了状态的有序性与可回溯性。
具体到前端的衍化中,在Angular
1兴起的时代实际上就已经开始了从直接操作Dom节点转向以状态/数据流为中心的变化,jQuery
代表着传统的以 DOM 为中心的开发模式,但现在复杂页面开发流行的是以 React
为代表的以数据/状态为中心的开发模式。应用复杂后,直接操作 DOM
意味着手动维护状态,当状态复杂后,变得不可控。React
以状态为中心,自动帮我们渲染出 DOM,同时通过高效的 DOM Diff
算法,也能保证性能。

小而美的视图层

React 与 VueJS 都是所谓小而美的视图层Library,而不是Angular
2这样兼容并包的Frameworks。任何一个编程生态都会经历三个阶段,第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。
React
并没有提供很多复杂的概念与繁琐的API,而是以最少化为目标,专注于提供清晰简洁而抽象的视图层解决方案,同时对于复杂的应用场景提供了灵活的扩展方案,典型的譬如根据不同的应用需求引入MobX/Redux这样的状态管理工具。React在保证较好的扩展性、对于进阶研究学习所需要的基础知识完备度以及整个应用分层可测试性方面更胜一筹。不过很多人对React的意见在于其陡峭的学习曲线与较高的上手门槛,特别是JSX以及大量的ES6语法的引入使得很多的传统的习惯了jQuery语法的前端开发者感觉学习成本可能会大于开发成本。与之相比Vue则是典型的所谓渐进式库,即可以按需渐进地引入各种依赖,学习相关地语法知识。比较直观的感受是我们可以在项目初期直接从CDN中下载Vue库,使用熟悉的脚本方式插入到HTML中,然后直接在script标签中使用Vue来渲染数据。随着时间的推移与项目复杂度的增加,我们可以逐步引入路由、状态管理、HTTP请求抽象以及可以在最后引入整体打包工具。这种渐进式的特点允许我们可以根据项目的复杂度而自由搭配不同的解决方案,譬如在典型的活动页中,使用Vue能够兼具开发速度与高性能的优势。不过这种自由也是有利有弊,所谓磨刀不误砍材工,React相对较严格的规范对团队内部的代码样式风格的统一、代码质量保障等会有很好的加成。
一言蔽之,Vue会更容易被纯粹的前端开发者的接受,毕竟从直接以HTML布局与jQuery进行数据操作切换到指令式的支持双向数据绑定的Vue代价会更小一点,特别是对现有代码库的改造需求更少,重构代价更低。而React及其相对严格的规范可能会更容易被后端转来的开发者接受,可能在初学的时候会被一大堆概念弄混,但是熟练之后这种严谨的组件类与成员变量/方法的操作会更顺手一点。便如Dan
Abramov所述,Facebook推出React的初衷是为了能够在他们数以百计的跨平台子产品持续的迭代中保证组件的一致性与可复用性。

1 从功能开发角度说,React的思路很好。
2 从页面设计角度说,传统的HTML+CSS以及同样思路的模板更好。

前端工程化的思考总结

下图展示了整个前端工程可能涉及到的各个环节,前端技术体系大局观一文覆盖式地简要介绍了各层系统的职能。

2757com 12

前端体系结构图

这里我结合自身的知识和实践经验,列出一些实现成本并不大并且性价比很高的工程化方案:

  1. **
    网络性能优化**:现在的web应用,大小动则上MB,加上一些静态资源,在目前我大天朝的网络环境下,在不做优化的基础下达到类似“首屏3s”或“动态加载xxs”的非功能性需求,需要付出很昂贵的硬件成本。目前网络优化主要有两个思路:CDN加速和缓存策略。对于前者,大公司往往采取自建CDN节点的方式,而小公司可以使用类似七牛云这样的云储存来进行静态资源的加速。而缓存策略则有许多的解决方案,有时还会牵扯到部署、迭代的问题。之后我会专门写一篇文章,介绍前端如何利用Webpack的Code
    Spliting和服务器的缓存机制来解决应用缓存与部署问题。(推荐这篇回答大公司里怎样开发和部署前端代码?)流量统计:这一块市面上已有非常成熟的方案,如CNZZ、百度站长统计等。当然也可以自己做一套,难度并不大,基本原理是在页面中拼装出标签,再远程加载javascript。

  2. 自动化部署系统:这个系统可以包含仓库代码管理、一键部署、一键Pull/Push,具体可以针对业务定制。它可以简化web应用从构建到上线的流程,提高效率,在快速迭代的web项目中非常有用。一个实现思路是利用后端服务调用预先编好的Shell脚本来完成命令行集操作,实现自动删除旧代码,clone新代码,安装环境等行为。

  3. 代码质量监控:可选的工具有JSLint和JSHint。前者对代码要求极为严格,后者对代码要求可以很宽松。Webstorm和PHPStorm已内置两种工具,个人推荐使用JSHint。
    除此之外,还有诸如日志系统、监控预警、自动化测试、API测试等细节领域,我还在探索阶段,这里就不过多赘述了~

渐隐的jQuery与服务端渲染

发表评论

电子邮件地址不会被公开。 必填项已用*标注