快捷搜索:

金沙第一娱乐娱城官网

当前位置:金沙第一娱乐娱城官网 > 金沙第一娱乐娱城官网 > 这个阶段涌现出了很多关注点相对集中、设计理

这个阶段涌现出了很多关注点相对集中、设计理

来源:http://www.dlksamusic.com 作者:金沙第一娱乐娱城官网 时间:2019-12-09 01:35

实体类

实体类其实就是静态类型语言,从工程上的意义而言就是可以统一数据规范,笔者在上文中提及过康威定律,设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。实体类,再辅以类似于TypeScript、Flow这样的静态类型检测工具,不仅可以便于IDE进行语法提示,还能尽可能地避免静态语法错误。同时,当业务需求发生变化,我们需要重组织部分业务逻辑,譬如修改某些关键变量名时,通过统一的实体类可以更方便安全地进行修改。同时,我们还需要将部分逻辑放置到实体类中进行,典型的譬如状态码与其描述文本之间的映射、部分静态变量值的计算等:

JavaScript

//零件关联的图纸信息 models: [ModelEntity] = []; cover: string = ''; /** * @function 根据推导出的零件封面地址 */ get cover() { //判断是否存在图纸信息 if (this.models && this.models.length > 0 && this.models[0].image) { return this.models[0].image; } return ''; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  //零件关联的图纸信息
  models: [ModelEntity] = [];
 
  cover: string = '';
 
  /**
   * @function 根据推导出的零件封面地址
   */
  get cover() {
 
    //判断是否存在图纸信息
    if (this.models && this.models.length > 0 && this.models[0].image) {
      return this.models[0].image;
    }
 
    return 'https://coding.net/u/hoteam/p/Cache/git/raw/master/2016/10/3/demo.png';
 
  }

同时在实体基类中,我们还可以定义些常用方法:

JavaScript

/** * @function 所有实体类的基类,命名为EntityBase以防与DOM Core中的Entity重名 */ export default class EntityBase { //实体类名 name: string = 'defaultName'; //默认构造函数,将数据添加到当前类中 constructor(data, self) { //判断是否传入了self,如果为空则默认为当前值 self = self || this; } // 过滤值为null undefined '' 的属性 filtration() { const newObj = {}; for (let key in this) { if (this.hasOwnProperty(key) && this[key] !== null && this[key] !== void 0 && this[key] !== '') { newObj[key] = this[key]; } } return newObj; } /** * @function 仅仅将类中声明存在的属性复制进来 * @param data */ assignProperties(data = {}) { let properties = Object.keys(this); for (let key in data) { if (properties.indexOf(key) > -1) { this[[key]] = data[[key]]; } } } /** * @function 统一处理时间与日期对象 * @param data */ parseDateProperty(data) { if (!data) { return } //统一处理created_at、updated_at if (data.created_at) { if (data.created_at.date) { data.created_at.date = parseStringToDate(data.created_at.date); } else { data.created_at = parseStringToDate(data.created_at); } } if (data.updated_at) { if (data.updated_at.date) { data.updated_at.date = parseStringToDate(data.updated_at.date) } else { data.updated_at = parseStringToDate(data.updated_at); } } if (data.completed_at) { if (data.completed_at.date) { data.completed_at.date = parseStringToDate(data.completed_at.date); } else { data.completed_at = parseStringToDate(data.completed_at); } } if (data.expiration_at) { if (data.expiration_at.date) { data.expiration_at.date = parseStringToDate(data.expiration_at.date); } else { data.expiration_at = parseStringToDate(data.expiration_at); } } } /** * @function 将类以JSON字符串形式输出 */ toString() { return JSON.stringify(Object.keys(this)); } /** * @function 生成随机数 * @return {string} * <a href="; */ _randomNumber() { let result = ''; for (let i = 0; i < 6; i++) { result += Math.floor(Math.random() * 10); } return result; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* @function 所有实体类的基类,命名为EntityBase以防与DOM Core中的Entity重名
*/
export default class EntityBase {
 
  //实体类名
  name: string = 'defaultName';
 
  //默认构造函数,将数据添加到当前类中
  constructor(data, self) {
 
    //判断是否传入了self,如果为空则默认为当前值
    self = self || this;
 
  }
  
  // 过滤值为null undefined '' 的属性
  filtration() {
    const newObj = {};
    for (let key in this) {
      if (this.hasOwnProperty(key) && this[key] !== null && this[key] !== void 0 && this[key] !== '') {
        newObj[key] = this[key];
      }
    }
    return newObj;
   }
 
  /**
   * @function 仅仅将类中声明存在的属性复制进来
   * @param data
   */
  assignProperties(data = {}) {
 
    let properties = Object.keys(this);
 
    for (let key in data) {
 
      if (properties.indexOf(key) > -1) {
        this[[key]] = data[[key]];
      }
 
    }
 
  }
 
  /**
   * @function 统一处理时间与日期对象
   * @param data
   */
  parseDateProperty(data) {
 
    if (!data) {
      return
    }
 
    //统一处理created_at、updated_at
    if (data.created_at) {
      if (data.created_at.date) {
        data.created_at.date = parseStringToDate(data.created_at.date);
      } else {
        data.created_at = parseStringToDate(data.created_at);
      }
    }
 
    if (data.updated_at) {
      if (data.updated_at.date) {
        data.updated_at.date = parseStringToDate(data.updated_at.date)
      } else {
        data.updated_at = parseStringToDate(data.updated_at);
      }
    }
 
    if (data.completed_at) {
      if (data.completed_at.date) {
        data.completed_at.date = parseStringToDate(data.completed_at.date);
      } else {
        data.completed_at = parseStringToDate(data.completed_at);
      }
    }
 
    if (data.expiration_at) {
      if (data.expiration_at.date) {
        data.expiration_at.date = parseStringToDate(data.expiration_at.date);
      } else {
        data.expiration_at = parseStringToDate(data.expiration_at);
      }
    }
 
  }
 
  /**
   * @function 将类以JSON字符串形式输出
   */
  toString() {
    return JSON.stringify(Object.keys(this));
  }
 
  /**
   * @function 生成随机数
   * @return {string}
   * <a href="http://www.jobbole.com/members/kaishu6296">@private</a>
   */
  _randomNumber() {
 
    let result = '';
    for (let i = 0; i < 6; i++) {
      result += Math.floor(Math.random() * 10);
    }
    return result;
  }
 
}

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

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

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

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已经是如此的优秀。

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

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

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

前后端分离与全栈:技术与人

前后端分离与全栈并不是什么新鲜的名词,都曾引领一时风骚。Web前后端分离优势显著,对于整个产品的开发速度与可信赖性有着很大的作用。全栈工程师对于程序员自身的提升有很大意义,对于项目的初期速度有一定增速。如果划分合理的话能够促进整个项目的全局开发速度与可信赖性,但是如果划分不合理的话只会导致项目接口混乱,一团乱麻。

我们常说的前后端分离会包含以下两个层面:

  • 将原本由服务端负责的数据渲染工作交由前端进行,并且规定前端与服务端之间只能通过标准化协议进行通信。
  • 组织架构上的分离,由早期的服务端开发人员顺手去写个界面转变为完整的前端团队构建工程化的前端架构。

前后端分离本质上是前端与后端适用不同的技术选型与项目架构,不过二者很多思想上也是可以融会贯通,譬如无论是响应式编程还是函数式编程等等思想在前后端皆有体现。而全栈则无论从技术还是组织架构的划分上似乎又回到了按照需求分割的状态。不过呢,我们必须要面对现实,很大程度的工程师并没有能力做到全栈,这一点不在于具体的代码技术,而是对于前后端各自的理解,对于系统业务逻辑的理解。如果我们分配给一个完整的业务块,同时,那么最终得到的是无数个碎片化相互独立的系统。

蛋疼的模块化与SPA

如果当时的移动网络速度可以更快的话,我想很多SPA框架就不存在了

随着踩得坑越来越多与类似于Backbone、AngularJs这样的更加纯粹全面的客户端框架的兴起,Single Page Application流行了起来。至此,在网页开发领域也就完全变成了CS这种理念。至此之后,我们会考虑在前端进行更多的用户交互与状态管理,而不是一股脑的全部交给后台完成。特别是页面的切换与不同数据的呈现不再是需要用户进行页面的跳转,从而在弱网情况下使用户获得更好的体验与更少的流量浪费。与此同时,前端就变得更加的复杂化,我们也迫切的需要更加完善的代码分割与管理方案,于是,笔者开始尝试接触模块化的东西。笔者自RequireJs、SeaJs兴起以来一直关注,但是从未在实际项目中投入使用。额,第一次用这两个框架的时候,发现貌似需要对现有的代码或者喜欢的jQuery Plugins进行封装,当时我这种懒人就有点心理阴影了。不过SeaJs作为早期国人开发的有一定影响力的前端辅助工具,笔者还是非常敬佩的。

前端扫盲-之打造一个自动化的前端项目

前端的工程化需求

当我们落地到前端时,笔者在历年的实践中感受到以下几个突出的问题:

  • 前后端业务逻辑衔接:在前后端分离的情况下,前后端是各成体系与团队,那么前后端的沟通也就成了项目开发中的主要矛盾之一。前端在开发的时候往往是根据界面来划分模块,命名变量,而后端是习惯根据抽象的业务逻辑来划分模块,根据数据库定义来命名变量。最简单而是最常见的问题譬如二者可能对于同意义的变量命名不同,并且考虑到业务需求的经常变更,后台接口也会发生频繁变动。此时就需要前端能够建立专门的接口层对上屏蔽这种变化,保证界面层的稳定性。
  • 多业务系统的组件复用:当我们面临新的开发需求,或者具有多个业务系统时,我们希望能够尽量复用已有代码,不仅是为了提高开发效率,还是为了能够保证公司内部应用风格的一致性。
  • 多平台适配与代码复用:在移动化浪潮面前,我们的应用不仅需要考虑到PC端的支持,还需要考虑微信小程序、微信内H5、WAP、ReactNative、Weex、Cordova等等平台内的支持。这里我们希望能够尽量的复用代码来保证开发速度与重构速度,这里需要强调的是,笔者觉得移动端和PC端本身是不同的设计风格,笔者不赞同过多的考虑所谓的响应式开发来复用界面组件,更多的应该是着眼于逻辑代码的复用,虽然这样不可避免的会影响效率。鱼与熊掌,不可兼得,这一点需要因地制宜,也是不能一概而论。

归纳到具体的技术点,我们可以得出如下衍化图:
金沙娱场app下载 1

声明式的渲染或者说可变的命令式操作是任何情况下都需要的,从以DOM操作为核心到数据流驱动能够尽量减少冗余代码,提高开发效率。笔者在这里还是想以jQuery与Angular 1的对比为例:

JavaScript

var options = $("#options"); $.each(result, function() { options.append($("<option />").val(this.id).text(this.name)); }); <div ng-repeat="item in items" ng-click="select(item)">{{item.name}} </div>

1
2
3
4
5
6
var options = $("#options");
$.each(result, function() {
    options.append($("<option />").val(this.id).text(this.name));
});
<div ng-repeat="item in items" ng-click="select(item)">{{item.name}}
</div>

目前React、Vue、Angular 2或其扩展中都提供了基于ES6的声明式组件的支持,那么在基本的声明式组件之上,我们就需要构建可复用、可组合的组件系统,往往某个组件系统是由我们某个应用的大型界面切分而来的可空单元组合而成,也就是下文前端架构中的解构设计稿一节。当我们拥有大型组件系统,或者说很多的组件时,我们需要考虑组件之间的跳转。特别是对于单页应用,我们需要将URL对应到应用的状态,而应用状态又决定了当前展示的组件。这时候我们的应用日益复杂,当应用简单的时候,可能一个很基础的状态和界面映射可以解决问题,但是当应用变得很大,涉及多人协作的时候,就会涉及多个组件之间的共享、多个组件需要去改动同一份状态,以及如何使得这样大规模应用依然能够高效运行,这就涉及大规模状态管理的问题,当然也涉及到可维护性,还有构建工具。现在,如果放眼前端的未来,当HTTP2普及后,可能会带来构建工具的一次革命。但就目前而言,尤其是在中国的网络环境下,打包和工程构建依然是非常重要且不可避免的一个环节。最后,从前端的项目类别上来看,可以分为以下几类:

  • 大型Web应用:业务功能极其复杂,使用Vue,React,Angular这种MVVM的框架后,在开发过程中,组件必然越来越多,父子组件之间的通信,子组件之间的通信频率都会大大增加。如何管理这些组件之间的数据流动就会成为这类WebApp的最大难点。
  • Hybrid Web APP:矛盾点在于性能与用户验证等。
  • 活动页面
  • 游戏

项目中的全栈工程师:技术全栈,需求隔离,合理分配

全栈工程师对于个人发展有很大的意义,对于实际的项目开发,特别是中小创公司中以进度为第一指挥棒的项目而言更具有非常积极的意义。但是全栈往往意味着一定的Tradeoff,步子太大,容易扯着蛋。任何技术架构和流程的调整,最好都不要去违背康威定律,即设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。有些全栈的结果就是强行按照功能来分配任务,即最简单的来说可能把登录注册这一块从数据库设计、服务端接口到前端界面全部分配给一个人或者一个小组完成。然后这个具体的执行者,因为其总体负责从上到下的全部逻辑,在很多应该规范化的地方,特别是接口定义上就会为了求取速度而忽略了必要的规范。最终导致整个系统支离破碎成一个又一个的孤岛,不同功能块之间表述相同意义的变量命名都能发生冲突,各种奇形怪状的id、uuid、{resource}_id令人眼花缭乱。

现代经济发展的一个重要特征就是社会分工日益精细明确,想要成为无所不知的通才不过南柯一梦。在自己的小团队中应该提倡职位轮替,一般某个项目周期完成后会调换部分前后端工程师的位置,一方面是为了避免繁杂的事务性开发让大家过于疲惫。另一方面也是希望每个人都了解对方的工作,这样以后出Bug的时候就能换位思考,毕竟团队内部矛盾,特别是各个小组之间的矛盾一直是项目管理中头疼的问题。

Webpack

Webpack跟browserify本质上都是module bundler,差异点在于Webpack提供更强大的loader机制让其更变得更加灵活。当然,Webpack的流行自然还是离不开背后的react 跟facebook。但是从现在HTTP/2标准的应用及实施进展来看,Webpack/browserify这种基于bundle的打包工具也面临着被历史车轮碾过的危机,相对的基于module loader的jspm反而更具前景。Browserify 可以让你使用类似于 node 的 require() 的方式来组织浏览器端的 Javascript 代码,通过预编译让前端 Javascript 可以直接使用 Node NPM 安装的一些库。相较于Webpack,Browserify具有更悠久的历史,记得当年还是看这篇文章才开始慢慢认识到Webpack,那时候Webpack还是一个相当年轻的框架啊。

Webpack是前端开发真正意义上成为了工程级别,而不再是随意,可以看看这篇文章。笔者第一次看Webpack的时候,没看懂。当时用Gulp用的正顺手,不需要自己往HTML文件里引入大量的Script文件,还能自动帮你给CSS加前后缀,自动地帮你压缩,多好啊。不过Grunt和Gulp现在存在的问题就是需要自己去组装大量的插件,参差不齐的插件质量导致了大量时间的浪费。并且Gulp/Grunt还并不能称为一个完整的编译工具,只是一个辅助工具。

Webpack还有很令笔者欣慰的一点,它支持Lazy Load Component,并且这种懒加载技术是与框架无关的。这样就避免了笔者在编码时还需要考虑固定的组件或者代码分割,毕竟在一个快速迭代的项目中还是很难在一开始就规划好全部的组件分割。这一点对于笔者这种被SPA JS加载以及原来的无论是基于Angular的懒加载还是React Router的懒加载折磨的人是一个大大的福音。同时,Webpack还支持配合了React Hot Loader的代码热插拔,可以大大地提高代码的开发效率。毕竟等着Browserify编译好也是很蛋疼的。

在笔者的个人的感触中,Webpack是促成了前端真正工程化的不可缺少的一环。记得之前看过美团的前端技术分享,它提出了前端分布式编译系统。大型系统的分布式编译很常见,但是在前端,这典型的脚本与解释执行的领域,出现了大型分布式编译系统,还是很让人震惊的。笔者是个懒惰的人,懒人总希望可以用一套方法去解决全部的问题,所以慢慢的笔者完全切入到了Webpack。或许未来某天也会离开Webpack,就像离开jQuery一样,但是会永远记得陪我走过的这些岁月。

项目中的全栈工程师:技术全栈,需求隔离,合理分配

  • full-stack-between-reality-and-wishful-thinking
  • 为什么你需要成为一个全栈开发工程师?

全栈工程师对于个人发展有很大的意义,对于实际的项目开发,特别是中小创公司中以进度为第一指挥棒的项目而言更具有非常积极的意义。但是全栈往往意味着一定的Tradeoff,步子太大,容易扯着蛋。任何技术架构和流程的调整,最好都不要去违背康威定律,即设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。这里是笔者在本文第一次提及康威定律,笔者在实践中发现,有些全栈的结果就是强行按照功能来分配任务,即最简单的来说可能把登录注册这一块从数据库设计、服务端接口到前端界面全部分配给一个人或者一个小组完成。然后这个具体的执行者,因为其总体负责从上到下的全部逻辑,在很多应该规范化的地方,特别是接口定义上就会为了求取速度而忽略了必要的规范。最终导致整个系统支离破碎成一个又一个的孤岛,不同功能块之间表述相同意义的变量命名都能发生冲突,各种奇形怪状的id、uuid、{resource}_id令人眼花缭乱。

今年年末的时候,不少技术交流平台上掀起了对于全栈工程师的声讨,以知乎上全栈工程师为什么会招黑这个讨论为例,大家对于全栈工程师的黑点主要在于:

  • Leon-Ready:全栈工程师越来越难以存在,很多人不过滥竽充数。随着互联网的发展,为了应对不同的挑战,不同的方向都需要花费大量的时间精力解决问题,岗位细分是必然的。这么多年来每个方向的专家经验和技能的积累都不是白来的,人的精力和时间都是有限的,越往后发展,真正意义上的全栈越没机会出现了。
  • 轮子哥:一个人追求全栈可以,那是他个人的自由。但是如果一个工作岗位追求全栈,然后还来鼓吹这种东西的话,那证明这个公司是不健康的、效率底下的。

现代经济发展的一个重要特征就是社会分工日益精细明确,想要成为无所不知的通才不过南柯一梦。不过在上面的声讨中我们也可以看出全栈工程师对于个人的发展是及其有意义的,它山之石,可以攻玉,融会贯通方能举一反三。笔者在自己的小团队中很提倡职位轮替,一般某个项目周期完成后会调换部分前后端工程师的位置,一方面是为了避免繁杂的事务性开发让大家过于疲惫。另一方面也是希望每个人都了解对方的工作,这样以后出Bug的时候就能换位思考,毕竟团队内部矛盾,特别是各个小组之间的矛盾一直是项目管理中头疼的问题。

金沙娱场app下载 2

纷扰

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

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

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

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

组件化的未来与Mobile-First

最初随着React的风靡,组件化的概念深入人心。笔者一直坚信组件化是非常值得去做的事情,它在工程上会大大提升项目的可维护性及拓展性,同时会带来一些代码可复用的附加效果。但这里要强调的一点是,组件化的指导策略一定是分治而不是复用,分治的目的是为了使得组件之间解耦跟正交,从而提高可维护性及多人协同开发效率。如果以复用为指导原则那么组件最后一定会发展到一个配置繁杂代码臃肿的状态。组件化最著名的标准无疑是W3C制定的Web Components标准,它主要包含以下几个方面:

  • <template>模板能力
  • ShadowDom 封装组件独立的内部结构
  • 自定义原生标签
  • imports解决组件间的依赖

不过这个标准本身还没发扬光大就被Angular、React这样的框架完爆了,不过他还是指明了我们组件化的几个准则:

  • 资源高内聚:有点像Vue提到的理念,Single File Component。组件资源内部高内聚,组件资源由自身加载控制
  • 作用域独立:内部结构密封,不与全局或其他组件产生影响
  • 自定义标签:可以像使用HTML的预设标签一样方便地使用组件
  • 可相互组合:组件正在强大的地方,组件间组装整合
  • 接口规范化:组件接口有统一规范,或者是生命周期的管理

纷扰之虹

笔者在前两天看到了Thomas Fuchs的一则Twitter,也在Reddit等社区引发了热烈的讨论:我们用了15年的时间来分割HTML、JS与CSS,然而一夕之间事务仿佛回到了原点。
金沙娱场app下载 3分久必合,合久必分啊,无论是前端开发中各个模块的分割还是所谓的前后端分离,都不能形式化的单纯按照语言或者模块来划分,还是需要兼顾功能,合理划分。笔者在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(妥协)。

工具化

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

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

所谓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 算法,也能保证性能。

AJAX与客户端开发

笔者最早的区分CS与BS架构,抽象来说,会认为CS是客户端与服务器之间的双向通信,而BS是客户端与服务端之间的单向通信。换言之,网页端本身也变成了有状态。从初始打开这个网页到最终关闭,网页本身也有了一套自己的状态,而拥有这种变化的状态的基础就是AJAX,即从单向通信变成了双向通信。图示如下:

金沙娱场app下载 4

解构设计稿

金沙娱场app下载 5

前言

近年来,随着浏览器性能的提升与移动互联网浪潮的汹涌而来,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 为代表的任务运行管理与以 WebpackRollupJSPM 为代表的项目打包工具各领风骚,帮助开发者更好的搭建前端构建流程,自动化地进行预处理、异步加载、Polyfill、压缩等操作。而以NPM/Yarn为代表的依赖管理工具一直以来保证了代码发布与共享的便捷,为前端社区的繁荣奠定了重要基石。

工程化与Builder

渐进的前端架构

笔者心中的前端架构如下所示,这里分别按照项目的流程与不同的开发时间应该开发的模块进行说明:

金沙娱场app下载 6

相辅相成的客户端渲染与服务端渲染

最初的网页是数据、模板与样式的混合,即以经典的APS.NET、PHP与JSP为例,是由服务端的模板提供一系列的标签完成从业务逻辑代码到页面的流动。所以,前端只是用来展示数据,所谓附庸之徒。而随着Ajax技术的流行,将WebAPP也视作CS架构,抽象来说,会认为CS是客户端与服务器之间的双向通信,而BS是客户端与服务端之间的单向通信。换言之,网页端本身也变成了有状态。从初始打开这个网页到最终关闭,网页本身也有了一套自己的状态,而拥有这种变化的状态的基础就是AJAX,即从单向通信变成了双向通信。

而近两年来随着React的流行服务端渲染的概念重回人们的视线。需要强调的是,我们现在称之为服务端渲染的技术并非传统的以JSP、PHP为代表的服务端模板数据填充,更准确的服务端渲染作用的描述是对于客户端应用的预启动与预加载。我们千方百计将客户端代码拉回到服务端运行并不是为了替换现有的API服务器,并且在服务端运行过的代码同样需要在客户端重新运行。

引入服务端渲染带来的优势主要在于以下三个方面:

  • 对浏览器兼容性的提升,目前React、Angular、Vue等现代Web框架纷纷放弃了对于旧版本浏览器的支持,引入服务端渲染之后至少对于使用旧版本浏览器的用户能够提供更加友好的首屏展示,虽然后续功能依然不能使用。

  • 对搜索引擎更加友好,客户端渲染意味着整体的渲染用脚本完成,这一点对于爬虫并不友好。虽然现代爬虫往往也会通过内置自动化浏览器等方式支持脚本执行,但是这样无形会加重很多爬虫服务器的负载,因此Google这样的大型搜索引擎在进行网页索引的时候还是依赖于文档本身。如果你希望提升在搜索引擎上的排行,让你的网站更方便地被搜索到,那么支持服务端渲染是个不错的选择。

  • 整体加载速度与用户体验优化,在首屏渲染的时候,服务端渲染的性能是远快于客户端渲染的。不过在后续的页面响应更新与子视图渲染时,受限于网络带宽与重渲染的范畴,服务端渲染是会弱于客户端渲染。另外在服务端渲染的同时,我们也会在服务端抓取部分应用数据附加到文档中,在目前HTTP/1.1仍为主流的情况下可以减少客户端的请求连接数与时延,让用户更快地接触到所需要的应用数据。

总结而言,服务端渲染与客户端渲染是相辅相成的,在React等框架的协助下我们也可以很方便地为开发阶段的纯客户端渲染应用添加服务端渲染支持。

渐隐的jQuery与服务端渲染

服务端渲染与路由

服务端渲染与路由可以参考Webpack2-React-Redux-Boilerplate。

小而美的视图层

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的初衷是为了能够在他们数以百计的跨平台子产品持续的迭代中保证组件的一致性与可复用性。

Web Components VS Reactive Components

对于Web组件化的典型代表,应该是React与Angular 2。Angular 2基本上完全革了Angular 1的命,Angular开发团队最早于2014年3月提出路线图,直到2015年底才进入alpha阶段。笔者自Angular 2开发之始就一直保持关注,见证了其规范或者接口的更迭。不可否认Angular 2在性能以及设计理念上都会比Angular 1先进很多,但是随着2014年中到2015年初以React为代表的组件式UI框架以及Flux/Redux为代表的响应式数据流驱动兴起,可能Angular 2并不会达到Angular 1的高度。笔者也在断断续续地更新一些Angular 2的指导与学习文档,不过确实,除了从零开始的大型项目,Angular 2还是太笨重了。

Will Angular 2 be a success? You bet!(注意,评论更精彩)

实际上,在我们选择一个库或者所谓的框架时,为我们的组件选择一个合适的抽象可能会比觉得哪个框架更好更有意义。目前Web的组件化开发分为两个大的趋势,一个是以Angular 2、Polymer为代表的Web Components,另一个是以React、Vue、Riot为代表的Reactive Components。目前Web Components方面因为各个库之间无法就如何定义它们达成一致,导致了类似于Angular 2、Aurelia这样的框架用它们自己的核心来定义Web Components。只有Polymer 100%实践了Web Components的规范。Web Components有点类似于Google,而React更像Facebook。

另外,当我们选择一个框架时,还需要考虑清楚我们是需要一个包含了所有的功能的固执己见的框架,就像Angular2、Ember 2这样的,还是一系列小的专精的框架的组合,就像React、Flux以及React Router这样的。当然,我们在选择一个框架时还必须考虑进它潜在的变化的代价与难度,以及与其他的技术集成的难度,还有就是他有没有一个完善的生态系统。

就像笔者在自己的[AARF]()提及的,无论前后端,在这样一样敏捷式开发与快速迭代地背景下,我们需要更多独立的分离的可以方便组合的类似于插件一样的模块。

延伸阅读

  • 尤雨溪:Vue 2.0,渐进式前端解决方案
  • 曹刘阳:2016年前端技术观察
  • 割裂的前端工程师:预测前端的2017
  • 张鑫:前端技术体系大局观
  • 2017年值得关注的JavaScript框架与主题
  • 2016年前端工具使用度调研报告
  • 2016年里做前端是怎样一种体验
  • 金沙娱场app下载,2016前端学习路线图
  • Web前端从入门菜鸟到实践老司机所需要的资料与指南合集

质量保障

前端开发完成并不意味着万事大吉,我们目前所谓的Bug往往有如下三类:

  • 开发人员的粗心大意造成的Bug:此类型Bug不可避免,但是可控性高,并且前端目前配置专门的辅助单元测试人员,此类型Bug最多在开发初期大规模出现,随着项目的完善会逐步减少。
  • 需求变动造成的Bug:此类型Bug不可避免,可控性一般,不过该类型Bug在正式环境下影响不大,最多影响程序员个人情绪。
  • 接口变动造成的Bug:此类型Bug不可避免,理论可控性较高。在上周修复的Bug中,此类型Bug所占比重最大,建议未来后端发布的时候也要根据版本划分Release或者MileStone,同时在正式上线后设置一定的灰度替代期,即至少保持一段时间的双版本兼容性。

基石与催化剂

相辅相成的客户端渲染与服务端渲染

  • Tradeoffs in server side and client side rendering
    Roy Thomas Fielding博士的Architectural Styles andthe Design of Network-based Software Architectures

笔者在2015-我的前端之路提及最初的网页是数据、模板与样式的混合,即以经典的APS.NET、PHP与JSP为例,是由服务端的模板提供一系列的标签完成从业务逻辑代码到页面的流动。所以,前端只是用来展示数据,所谓附庸之徒。而随着Ajax技术的流行,将WebAPP也视作CS架构,抽象来说,会认为CS是客户端与服务器之间的双向通信,而BS是客户端与服务端之间的单向通信。换言之,网页端本身也变成了有状态。从初始打开这个网页到最终关闭,网页本身也有了一套自己的状态,而拥有这种变化的状态的基础就是AJAX,即从单向通信变成了双向通信。图示如下:

金沙娱场app下载 7

上文描述的即是前后端分离思想的发展之路,而近两年来随着React的流行服务端渲染的概念重回人们的视线。需要强调的是,我们现在称之为服务端渲染的技术并非传统的以JSP、PHP为代表的服务端模板数据填充,更准确的服务端渲染作用的描述是对于客户端应用的预启动与预加载。我们千方百计将客户端代码拉回到服务端运行并不是为了替换现有的API服务器,并且在服务端运行过的代码同样需要在客户端重新运行,这里推荐参考笔者的Webpack2-React-Redux-Boilerplate,按照三个层次地渐进描述了从纯客户端渲染到服务端渲染的迁移之路。引入服务端渲染带来的优势主要在于以下三个方面:

  • 对浏览器兼容性的提升,目前React、Angular、Vue等现代Web框架纷纷放弃了对于旧版本浏览器的支持,引入服务端渲染之后至少对于使用旧版本浏览器的用户能够提供更加友好的首屏展示,虽然后续功能依然不能使用。
  • 对搜索引擎更加友好,客户端渲染意味着整体的渲染用脚本完成,这一点对于爬虫并不友好。虽然现代爬虫往往也会通过内置自动化浏览器等方式支持脚本执行,但是这样无形会加重很多爬虫服务器的负载,因此Google这样的大型搜索引擎在进行网页索引的时候还是依赖于文档本身。如果你希望提升在搜索引擎上的排行,让你的网站更方便地被搜索到,那么支持服务端渲染是个不错的选择。
  • 整体加载速度与用户体验优化,在首屏渲染的时候,服务端渲染的性能是远快于客户端渲染的。不过在后续的页面响应更新与子视图渲染时,受限于网络带宽与重渲染的范畴,服务端渲染是会弱于客户端渲染。另外在服务端渲染的同时,我们也会在服务端抓取部分应用数据附加到文档中,在目前HTTP/1.1仍为主流的情况下可以减少客户端的请求连接数与时延,让用户更快地接触到所需要的应用数据。

总结而言,服务端渲染与客户端渲染是相辅相成的,在React等框架的协助下我们也可以很方便地为开发阶段的纯客户端渲染应用添加服务端渲染支持。

工程化

所谓工程化,即是面向某个产品需求的技术架构与项目组织,工程化的根本目标即是以尽可能快的速度实现可信赖的产品。尽可能短的时间包括开发速度、部署速度与重构速度,而可信赖又在于产品的可测试性、可变性以及Bug的重现与定位。

  • 开发速度:开发速度是最为直观、明显的工程化衡量指标,也是其他部门与程序员、程序员之间的核心矛盾。绝大部分优秀的工程化方案首要解决的就是开发速度,我们在追寻局部速度最快的同时不能忽略整体最优,初期单纯的追求速度而带来的技术负债会为以后阶段造成不可弥补的损害。
  • 部署速度:程序员在日常工作中,最常对测试或者产品经理说的一句话就是,我本地改好了,还没有推送到线上测试环境呢。在DevOps概念深入人心,各种CI工具流行的今天,自动化编译与部署帮我们省去了很多的麻烦。但是部署速度仍然是不可忽视的重要衡量指标,特别是以NPM为代表的难以捉摸的包管理工具与不知道什么时候会抽个风的服务器都会对我们的编译部署过程造成很大的威胁,往往项目依赖数目的增多、结构划分的混乱也会加大部署速度的不可控性。
  • 重构速度:听产品经理说我们的需求又要变了,听技术Leader说最近又出了新的技术栈,甩现在的十万八千里。
  • 可测试性:现在很多团队都会提倡测试驱动开发,这对于提升代码质量有非常重要的意义。而工程方案的选项也会对代码的可测试性造成很大的影响,可能没有无法测试的代码,但是我们要尽量减少代码的测试代价,鼓励程序员能够更加积极地主动地写测试代码。
  • 可变性:程序员说:这个需求没法改啊!
  • Bug的重现与定位:没有不出Bug的程序,特别是在初期需求不明确的情况下,Bug的出现是必然而无法避免的,优秀的工程化方案应该考虑如何能更快速地辅助程序员定位Bug。

无论是前后端分离,还是后端流行的MicroService或者是前端的MicroFrontend,其核心都是牺牲局部开发速度换来更快地全局开发速度与系统的可信赖性的提高。而区分初级程序员与中级程序员的区别可能在于前者仅会实现,仅知其然而不知其所以然,他们唯一的衡量标准就是开发速度,即功能实现速度或者代码量等等,不一而足。中级程序员则可以对自己负责范围内的代码同时兼顾开发速度与代码质量,会在开发过程中通过不断地Review来不断地合并分割,从而在坚持SRP原则的基础上达成尽可能少的代码量。另一方面,区分单纯地Coder与TeamLeader之间的区别在于前者更注重局部最优,这个局部即可能指项目中的前后端中的某个具体模块,也可能指时间维度上的最近一段的开发目标。而TeamLeader则更需要运筹帷幄,统筹全局。不仅仅要完成老板交付的任务,还需要为产品上可能的修改迭代预留接口或者提前为可扩展打好基础,磨刀不误砍材工。总结而言,当我们探究工程化的具体实现方案时,在技术架构上,我们会关注于:

  • 功能的模块化与界面的组件化
  • 统一的开发规范与代码样式风格,能够在遵循SRP单一职责原则的前提下以最少的代码实现所需要的功能,即保证合理的关注点分离。
  • 代码的可测试性
  • 方便共享的代码库与依赖管理工具
  • 持续集成与部署
  • 项目的线上质量保障

渐隐的jQuery

jQuery作为了影响一代前端开发者的框架,是Tools的典型代表,它留下了璀璨的痕迹与无法磨灭的脚印。笔者在这里以jQuery作为一个符号,来代表以Dom节点的操作为核心的一代的前端开发风格。那个年代里,要插入数据或者更改数据,都是直接操作Dom节点,或者手工的构造Dom节点。譬如从服务端获得一个用户列表之后,会通过构造<i>节点的方式将数据插入到Dom树中。

但是不得不承认,在未来相当长的一段时间内,jQuery并不会直接退出历史的舞台,笔者个人认为一个重要的原因就是现在仍然存在着很大比重的各式各样的基于jQuery的插件或者应用,对于崇尚拿来主义的我们,不可避免的会继续使用着它。

You-Dont-Need-jQuery

jQuery引领了一个辉煌的时代,但是随着技术的演进它也慢慢在很多项目中隐去。jQuery这个框架本身非常的优秀并且在不断的完善中,但是它本身的定位,作为早期的跨浏览器的工具类屏蔽层在今天这个浏览器API逐步统一并且完善的今天,逐渐不是那么关键。因此,笔者认为jQuery会逐渐隐去的原因可能为:

  • 现代浏览器的发展与逐步统一的原生API

由于浏览器的历史原因,曾经的前端开发为了兼容不同浏览器怪癖,需要增加很多成本。jQuery 由于提供了非常易用的 API,屏蔽了浏览器差异,极大地提高了开发效率。这也导致很多前端只懂 jQuery。其实这几年浏览器更新很快,也借鉴了很多 jQuery 的 API,如querySelectorquerySelectorAll 和 jQuery 选择器同样好用,而且性能更优。

  • 前端由以DOM为中心到以数据/状态为中心

jQuery 代表着传统的以 DOM 为中心的开发模式,但现在复杂页面开发流行的是以 React 为代表的以数据/状态为中心的开发模式。应用复杂后,直接操作 DOM 意味着手动维护状态,当状态复杂后,变得不可控。React 以状态为中心,自动帮我们渲染出 DOM,同时通过高效的 DOM Diff 算法,也能保证性能。

  • 不支持同构渲染与跨平台渲染

React Native中不支持jQuery。同构就是前后端运行同一份代码,后端也可以渲染出页面,这对 SEO 要求高的场景非常合适。由于 React 等流行框架天然支持,已经具有可行性。当我们在尝试把现有应用改成同构时,因为代码要运行在服务器端,但服务器端没有 DOM,所以引用 jQuery 就会报错。这也是要移除 jQuery 的迫切原因。同时不但要移除 jQuery,在很多场合也要避免直接操作 DOM。

  • 性能缺陷

jQuery的性能已经不止一次被诟病了,在移动端兴起的初期,就出现了Zepto这样的轻量级框架,Angular 1也内置了jqlite这样的小工具。前端开发一般不需要考虑性能问题,但你想在性能上追求极致的话,一定要知道 jQuery 性能很差。原生 API 选择器相比 jQuery 丰富很多,如 document.getElementsByClassName金沙第一娱乐娱城官网, 性能是 $(classSelector) 的 50 多倍!

金沙娱场app下载 8

说这么多,只是想在以后技术选型的时候,能有一个通盘考虑,毕竟,这是曾经的Best Love。

本文由金沙第一娱乐娱城官网发布于金沙第一娱乐娱城官网,转载请注明出处:这个阶段涌现出了很多关注点相对集中、设计理

关键词:

上一篇:即渐进式web应用,原文出处

下一篇:没有了