我是 Angular 的新手,但我已经听说过(和 read )一些关于它的渲染模型的“谣言”,以及它与 React 等不同之处。
我读过 Angular 专家的一些帖子,他们声称如果您必须使用 Angular 渲染长列表,它可能会很慢,因为如果发生变化,Angular 会重新渲染整个列表,而 React(例如)“一旦它已经呈现,将不会从头开始重新呈现整个列表,但它会在内部跟踪呈现的 DOM 元素,并在新调用时创建新的虚拟 DOM,将其与前一个进行比较并仅应用更改”
(引自一篇关于 Angular 渲染问题的随机博文)
所以当我开始学习 Angular 时,我的第一件事就是尝试这个。
而且我似乎无法重现这个问题......
这是一个虚拟的 Plunker,我 created重现问题。
您可以将新项目添加到使用 ng-repeat 呈现的消息列表中,如下所示:
<table>
<tr ng-repeat="m in messages" class="{{name}}">
<td>{{m.message}}</td>
<td>{{m.date}}</td>
</tr>
</table>
你可以点击一个按钮来更新一个这样的项目,你可以更新另一个与列表完全无关的属性(name
)
现在,如果我打开开发人员工具栏,修改表中项目的 HTML 属性,然后单击“添加新消息”,我的修改不会丢失或被 Angular 覆盖 - 似乎 Angular 不会完全重新渲染 DOM。看起来还挺聪明的。
Angular 最近开始使用 DOM diffing 了吗? (我的演示使用 Angular 1.4.0 beta)
只是因为从 DOM 渲染的 Angular 来看,我只是看不出 React 和 Angular 之间有什么大的区别。
你能给我展示一个用例来说明 Angular 渲染模型的缺点吗?
最佳答案
关于这个主题有很多混淆,主要是因为它不是简单的“Angular 重新渲染一切”类型的答案。
Angular 数据绑定(bind)的基础(在 1.x 版本中)围绕着 $digest
循环和 $scope
的概念。 $scope
是一个特殊对象,它“ self 跟踪”它的属性,并使用 $scope.$watch()
方法为每个属性创建一个 JavaScript 事件监听器。这些监听器监视对 HTML 中的 changeable 输入元素和 $scope
属性的更改。
每当任何 JavaScript 监听器触发时,$digest
循环循环遍历 $watch
下的每个项目并适本地更新值。您还可以调用 $scope.$apply()
来手动执行 $digest
循环。此循环可以执行多次,因为对一个值的更改会影响 $watch
下的另一个值,从而触发另一个 $digest
。但是,$digest
循环确实有一个迭代上限以确保它在循环引用时停止。
当您处理对象数组和特殊指令 ng-repeat
时,麻烦就来了。默认情况下,$watch()
函数只检查对象引用是否相等。在每个 $digest
中,AngularJS 将检查新值和旧值是否是相同的“物理”对象,并且仅当您实际更改了底层对象引用时才会调用其处理程序。
为了解决这个问题,ng-repeat
创建了它自己独特的 scope
。这允许数组中的每个元素都有一个唯一的 $watch
。这里的挑战是,如果数组本身发生变化,那么这个唯一的 scope
将与所有 $watch
元素一起重新生成。压入、弹出、拼接数组可以创建许多 $watch
值。
Angular 提供了几种方法来处理这个问题。
在 1.3 中添加的新的 Bind Once 语法允许只在表达式被计算之前存在的监听器。 ng-repeat="element in::elements"
将遍历数组,填充 DOM,然后销毁事件监听器。这非常适合 DOM 元素在评估后不会更改的情况。
使用 track by
也可以积极地跟踪元素。 ng-repeat="element in elements track by $id"
将在唯一的 $id
值上创建一个 $watch
,而不是元素的数组中的位置。这允许更稳定的 $watch
传播,并且在元素的值可能发生变化的情况下是理想的。
至于为什么你在控制台中所做的更改没有丢失:首先,开发者控制台中的更改不会触发任何事件监听器。其次,只有当 $watch
检测到变化时,您更改的特定 DOM 元素才会被修改。然而,这并不是真正的 HTML 的“差异”;可以这么说,Angular 不是“看 HTML”,而是“看数据”。
关于javascript - Angular 是否使用 DOM 差异化或必须为每个列表项设置 "re-render"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29067988/