angular DEV模式更改检测 - 在后续检查中,如果对象引用发生变化,则显示警告,

btqmn9zl  于 2个月前  发布在  Angular
关注(0)|答案(5)|浏览(59)

🚀功能请求

相关包

此功能请求适用于 @angular/core

描述

当Angular进行变更检测时,它会在属性绑定更改时重新渲染视图。Angular对于“什么”被认为是“改变”存在一个小问题。如果对象引用更改为与第一个对象相同的对象,即使视图最终与之前相同,Angular也会使用这个新对象更新视图。这种情况很容易让新手陷入困境,因为编写一个类似于以下的函数很容易:

divClasses() {
  return {
    red: this.isRed
  };
}

然后将其绑定到一个 [ngClass] 指令,这将在每次变更检测调用时删除并重新应用 red 类,因为 divClasses() 每次运行时都会返回一个新对象。

<div [ngClass]="divClasses()"></div><!-- This div will be updated every time change detection is ran. -->

这导致了两个大问题,第一个是低效的视图渲染。变更检测只需要在组件的 isRed 值更改时更新视图,但它最终每次都更新视图。这将降低页面速度并对最终用户的经验产生负面影响。
不太明显的问题是变更检测递归的可能性。如果应用程序有一个 MutationObserver ,用于监视DOM更改,上面的函数将导致每次变更检测运行时都运行它。如果这个 MutationObserver 也触发了一个变更检测检查,页面将挂起,因为 divClasses() 函数更新了视图,触发了 MutationObserver ,从而再次触发变更检测。这甚至可能不是开发者的错,因为 MutationObserver 可能来自第三方库。
我最近花了一天半的时间尝试调试以这种方式挂起的应用程序。有趣的是,由于第三方库修改了 console.log 以运行变更检测 - 导致递归再次发生。最终,我怀疑这种情况可能是诸如 valor-software/ngx-bootstrap#3047#20450#24614 等问题的原因。

描述你希望解决的方案

要明确的是,我提出的“修复”并不涉及修改Angular的变更检测来进行深度对象引用比较。关于此错误的讨论: #24614 最终被搁置,因为提议的修复涉及深度相等检查,这将非常低效且耗时地检查较大的对象。
最终,这里似乎存在的问题是像我的示例 divClasses() 这样的函数,它们无意中滥用变更检测来不必要地更新视图。如果有一种方法可以警告开发人员他们编写的函数可能是有问题的,那可能会是最好的方法。
目前,Angular在开发模式下运行应用程序时会显示类似的警告来处理类似的情况。如果变更检测本身会导致属性/函数更改其输出,Angular目前会显示有关发生了什么的警告。是否有可能在每次函数返回不同的对象引用时显示类似的警告?引用检查不会花费很多钱,这可能会帮助应用程序开发人员优化他们的程序。

wydwbb8l

wydwbb8l1#

@ibedard16 我认为你误解了 #24614 背后的原因。该票并未要求进行深入比较。它只是指出使用返回对象的 getter 可能在生产环境中产生不可恢复的副作用,如果我们在开发模式下或在lint时间有警告就好了。

yshpjwxd

yshpjwxd2#

请注意,我们已经开始了针对您的功能请求的社区投票过程。距离投票过程结束还有20天。
有关Angular功能请求流程的更多详细信息,请参阅我们的文档。

46scxncf

46scxncf3#

根据我阅读#24614的了解,你的bug报告描述了我正在尝试通过这个功能请求解决的问题。我之前说你的bug报告“提出了一个修复方案”是错误的——你的报告只是描述了问题,并寻求解决方案。
在阅读你的bug报告线程后,报告在讨论转向“深度变化检测”时被关闭。然后者认为解决你的bug需要深度变化检测(实际上并不需要)。深度变化检测显然是一个糟糕的想法——我不认为我在这里需要解释为什么。
你确实建议在变化检测花费太长时间执行单个函数时显示警告/错误消息(#24614)。虽然我同意这种情况值得发出警告,但我不确定这应该是显示警告信息的条件。
我发起这个功能请求是因为我认为开发模式下的变化检测过程中的警告是一个合理的修复方案。关于是否会在这种情况下抛出“Expression has changed after it was checked”警告有过简短的讨论,因为对象引用确实在发生变化。不幸的是,当对象引用发生变化时,那个警告不会被抛出——所以它不会出现在这个场景中。
对于造成的困惑和这次迟来的回复,我很抱歉。

dwbf0jvd

dwbf0jvd4#

感谢您提交您的功能请求!看起来在投票过程中,它没有收集到足够的票数进入下一阶段。
我们希望保持Angular丰富且符合人体工程学,同时关注其范围和学习过程。如果您认为您的请求可能超出了Angular的范围,我们鼓励您与community合作,将其发布为开源项目package
您可以在我们的文档中找到有关功能请求过程的更多详细信息。

9avjhtql

9avjhtql5#

相关 [#25518](https://github.com/angular/angular/issues/25518)

相关问题