文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

大多数互动的单页应用都是使用JavaScript(JS)框架和库来构建的。 用于快速单页应用( SPA)开发的JS工具的数量在持续地增长,使得对于我们web开发人员来说,选择依赖哪个技术更具有挑战性。

React和Angular目前都在美国、英国、加拿大、法国、德国、澳大利亚及其他国家的很多商业、新闻和旅行公司中被使用到。自2009发布以来,AngularJS已被列入几乎所有的十大JavaScript框架列表中。这个模型-视图-控制器框架在web开发人员中变得非常流行。ReactJS甚至被JavaScript编程人员更广泛地使用,虽然它其实是个库,而不是一个框架;React库只有视图层,没有模型层和控制器组件。因此,React是怎么变得流行的,我们又应该如何合理地对一个框架(AngularJS)和一个库(ReactJS)作JavaScript框架的比较

第 1 段(可获 1.93 积分)

AngularJS(框架)和ReactJS(库)之间的主要差异在于以下方面:组件化、数据绑定、性能、依赖性解析、指令和模板。让我们对这些方面逐个地进行研究。

组件化

AngularJS

AngularJS有一个非常复杂的固定结构,因为它是基于三层——模型层、视图层和控制器——一个典型的单页应用程序。在AngularJS里,一个对象的$scope负责模型部分,模型部分被控制器初始化,然后转换成HTML以为用户创建视图层。 Angular有很多标准的服务、工厂、控制器、指令和其他组件,对于一个JavaScript开发人员来说,最初的学习掌握需要一定的时间。

第 2 段(可获 1.4 积分)

使用AngularJS,我们将应用程序代码分成几个文件。例如,当我们用自己的指令、控制器和模板创建一个可重用的组件时,我们必须在一个单独的文件中描述每个代码块。指令描述完成后,我们需要在指令中添加一个链接到我们的模板,以耦合这些部分。AngularJS指令表示了你的应用的模板逻辑。模板是用Angular指令扩展的HTML,通常被写为标签或属性。我们还需要添加控制器来给我们的数据模型添加必要的$scope(范围)或上下文。控制器也需要写入到另一个单独的文件中。如果我们用这样的方式模块化我们的应用, 我们就可以在网站的其他部分重用我们的模板或组件。

第 3 段(可获 1.54 积分)

ReactJS

创建了ReactJS的Facebook选择了一个不同于AngularJS以及类似的MVC框架结构的架构。简而言之,使用ReactJS构件的应用没有“正确的”结构。

ReactJS是一个大型JavaScript库,它可以帮助我们为用户更新视图层。但只有ReactJS,我们仍然不能创建应用程序。 这个库缺少模型层和控制器层。为了填补这个空白,Facebook引入了Flux,来控制应用的工作流。Flux现在有许多变体。

ReactJS提供了一种非常简单有效的构建组件树的方法。它拥有函数式编程风格,在这种风格下,组件定义是声明性的。用ReactJS组件构成你的应用就像用函数构成一个JavaScript程序。看看下面这个从GitHub拿来的例子:

第 4 段(可获 1.61 积分)
var TodoApp =React.createClass({
getInitialState:function () {
return {
nowShowing:app.ALL_TODOS,
editing:null,
newTodo:''
};
},
handleChange:function (event) {
this.setState({
newTodo:event.target.value
});
}
});
// 为了简洁,省略了其他代码

由于组件的可用性,用ReactJS编写的代码逻辑结构严密而且可读。ReactJS库不需要你以某种方式编写代码。它建议你使用JSX(一个类似于XML语法的特殊语法)来创建你的类和模板,但编写原生avaScript和HTML也是可以的。这使JavaScript开发人员能够更容易适应React应用程序,因为不需要学习不寻常的语法。React提供了一个AngularJS没有的自由。但这种自由的代价是要花费额外的时间去设计一个应用程序的结构。在我们开始一个新的项目之前,我们必须考虑我们将使用什么工具。当你必须从100个工具中选择一个工具来解决单个任务时,这个选择变得十分麻烦。

第 5 段(可获 1.7 积分)

数据绑定

AngularJS

AngularJS通过控制器使用双向数据绑定连接文档对象模型(DOM)值到模型数据。简而言之,如果用户和一个<input>字段相互作用,并给应用程序提供一个新的值,那么,不止视图被更新,模型也会。双向数据绑定对于AngularJS来说是有益的,因为它能够帮助我们编写更少的样板代码来创建应用的组件之间(视图和模型)的相互作用。我们不需要发明一种用来跟踪应用程序的修改和相应地修改我们的JavaScript代码的方法。

第 6 段(可获 1.24 积分)

Angular的双向数据绑定方式的缺点在于它对于性能的负面影响。Angular自动了为每个绑定都创建了观察者。在开发过程中,当一个应用程序为绑定元素创建的观察者很多的时候,我们可能会得出上面的这个结论。

ReactJS

React使用单向数据绑定,这意味着我们可以只在一个方向上引导数据流。由于这个原因,数据在哪里发生改变总是很清楚。值得注意的是,由于ReactLink的存在,双向数据绑定在v15前的ReactJS是可用的。

ReactJS Flux workflow

为了在React中实现单向数据流,Facebook创建了自己的应用程序架构Flux。Flux通过一个控制点——分发器对ReactJS组件控制数据流。Flux的分发器接收一个对象(它们称之为一个action),然后把这个对象转移到一个适当的存储空间,这个存储空间会自行更新。更新一旦完成,视图相应地发生改变,并发送一个新的action到分发器。只有在一个action被完全更新时,才将其转移到存储区。基于这个概念,Flux提高了代码库的有效性。根据我们自己的经验,我们可以说,当你需要处理动态更新的数据时,Flux是很好用的。

第 7 段(可获 2.63 积分)

ReactJS的单向数据流保持了可以控制的复杂度。调试大型ReactJS应用程序的独立组件比起调试类似规模的AngularJS应用程序要简单得多。

性能

AngularJS

当我们谈论Angular的性能时,需要考虑两件事情。正如我们之前提到过的一样,Angular 1.x和更高版本都依赖于双向数据绑定。 这个概念是基于“脏检查”,一种可以使我们的AngularJS应用延迟的机制,的。

当我们在HTML中给我们的模型绑定值时,Angular给每个绑定创建一个观察者(watcher),以追踪DOM发生的变化。一旦视图层更新(变“脏”),Angular就会用初始值(被绑定的)对比新的值,并执行$digest循环。然后,$digest循环检查实际发生更改的值和其他通过观察者追踪的值。这就是为什么如果你的应用程序有太多的观察者,性能会下降很多。当多个值(视图)相互依赖时,这个缺点更令人痛苦。一旦Angular看到 一个值的改变是由另一个值触发的,它就会停止当前的$digest循环, 再次重新执行它。

第 8 段(可获 2.54 积分)

直到检查了所有的观察者并对视图和模型都应用了必要的修改之后,循环才会停止工作。在实践中,我们可以给不同的视图和模型绑定一个 <input>域。当用户在域中输入了新的数据,改变也许不是立即可见的。我们最好避免这种情况。

 AngularJS框架的另一个缺点是它处理DOM的方式。和不同,AngularJS把改变应用于浏览器中真正的DOM。当真正的DOM得到更新,浏览器必须改变很多内部的值,以代表一个新的DOM。这也会对应用程序的性能造成负面影响。

第 9 段(可获 1.4 积分)

性能不佳也是Angular 2支持者引入与React类似的服务器端的虚拟文档对象模型(DOM)渲染和单向数据绑定的主要原因。尽管如此,Angular 2仍然支持可选的双向数据绑定。

ReactJS

ReactJS的创造者引入了虚拟文档对象模型的概念,这被视为ReactJS和其他成熟框架,包括AngularJS,对比的最大优点之一。虚拟的DOM是如何工作的呢?当我们的HTML文档被加载,ReactJS就会从JavaScript对象创建一个轻量级的DOM树,在服务器端保存起来。例如,当用户在 <input>  域输入一个新数据的时候,React会创建一个新的虚拟DOM,然后和之前保存的DOM进行对比。库用这种方式寻找两个对象模型的差异,并用新的发生了改变的HTML再一次重建虚拟DOM。所有的这些工作都是在服务器端完成的,这减少了浏览器的负载。

第 10 段(可获 2.05 积分)

现在,React只发送发生了改变的元素的HTML,而不是发送全新的HTML到浏览器。这种方式比AngularJS提供的更高效。

对于单向数据绑定,React不使用观察者来跟踪在真实DOM上发生的变化。 总的来说,ReactJS使得控制应用程序的性能更加简单。但这并不意味着我们用AngularJS不能创建一个快速的应用程序。

解决依赖关系

AngularJS

AngularJS使用一个叫做依赖注入的基本面向对象(OOP)编程模式,这意味着我们可以在一个单独的文件中编写依赖关系。在对象中直接创建依赖是不方便的。在AngularJS中,依赖注入是所有我们为一个Angular工厂或者服务声明的标准函数所固有的。我们只需要在我们的函数中,像传递任意排序的参数那样传递依赖。这是普通的JavaScript和Angular的不同之处,因为参数的顺序在标准的JS中是被严格规定的。

第 11 段(可获 1.89 积分)
angular.module('todomvc')
// Angular injects four dependencies in the TodoCtrl function – $scope, $routeParams, $filter, and store;
.controller('TodoCtrl', functionTodoCtrl($scope, $routeParams, $filter, store) {
'use strict';
var todos =$scope.todos=store.todos;
$scope.newTodo='';
$scope.editedTodo=null;
// missing function code is omitted for brevity
});

Angular 可自动的查找合适的对象并注入到 $routeParams, $filter, store 和 $scope 参数中。Angular 框架中提供两个函数用来实现依赖注入,分别是 $inject 和 $provide.

第 12 段(可获 0.4 积分)

在AngularJS中,依赖注入还带来了一个问题;当你的代码缩小时,可能会出现的一个有点令人讨厌的东西。

为了简洁,一个代码缩小程序会减少依赖的名称到像$b和$y这样的形式。但当你执行代码的时候,Angular会以它们实际的名字寻找依赖,例如上例中的$scope、$filter和store!这是我们的程序在默默地崩溃的时候。从乐观的角度上看,这个问题很容易被解决。

正如你从下面的例子可以看到的,我们已经声明了函数TodoCtrl而且只传递参数的短名字。在下面的例子中,我们进一步在我们的函数中明确地展示了应该依照顺序注入什么。因此,“s”参数代表了“$scope”;“r”参数代表了“$routeParams”,以此类推。Angular会自动找到依赖。这一次,必须要注意参数的顺序。

第 13 段(可获 1.81 积分)
// an example from GitHub
angular.module('todomvc')
.controller('TodoCtrl', TodoCtrl);

functionTodoCtrl(s, r, f, a) {
'use strict';
var todos =s.todos=a.todos;
s.newTodo='';
s.editedTodo=null;
// missing function code is omitted for brevity
};
//inject dependencies using a special function
TodoCtrl[“inject”] = [“$scope”, “$routeParams”, “$filter”, “store”];

还有另外一种方法用来传递函数以及其依赖的,那就是数组。首个数组元素是依赖,紧接着是函数以及所需的参数。

第 14 段(可获 0.39 积分)

如何将依赖项注入到Angular模块中的另一个例子:

[“$scope”, “$routeParams”, “$filter”, “store”, functionTodoCtrl(s, r, f, a) { //your code goes here }];

ReactJS

React和Angular之间在依赖注入上的区别是,React不伪依赖注入提供任何内置容器的概念。但这并不意味着在我们的ReactJS项目中我们必须想到一种方法来注入依赖。在一个React应用程序中,你可以使用很多仪器来自动注入依赖。这样的仪器有Browserify、RequireJS、EcmaScript 6模块,我们可以通过Babel、ReactJS-di等使用到这些仪器。选择哪个工具是我们唯一的难题。

第 15 段(可获 1.21 积分)

文章评论