23

记一次解决错误:ExpressionChangedAfterItHasBeenCheckedError - 成长之路 - Segment...

 4 years ago
source link: https://segmentfault.com/a/1190000020886310
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

问题的出现

在写本周的实验时又发现了一个以前没有注意到的angular的报错

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngForOf: [object Object]'. Current value: 'ngForOf: undefined'.

image.png

网上找了找出现这个的原因,大概就是视图层显示的数据和c层的数据不一致造成的

为何会出现

视图都成功的渲染出来了,为什么还会报错呢?

先来了解一下angular的渲染流程

angular的渲染流程

Angular 程序其实是一个组件树,在变更检测期间,Angular 会按照以下顺序检查每一个组件(注:这个列表称为列表 1):

  • 更新所有子组件/指令的绑定属性
  • 调用所有子组件/指令的三个生命周期钩子:ngOnInitOnChangesngDoCheck
  • 更新当前组件的 DOM
  • 为子组件执行变更检测(注:在子组件上重复上面三个步骤,依次递归下去)
  • 为所有子组件/指令调用当前组件的ngAfterViewInit生命周期钩子

在每一次操作后,Angular 会记下执行当前操作所需要的值,并存放在组件视图的oldValues属性里(注:Angular Compiler 会把每一个组件编译为对应的 view class,即组件视图类)。在所有组件的检查更新操作完成后,Angular 并不是马上接着执行上面列表中的操作,而是会开始下一次digest cycle,即 Angular 会把来自上一次 digest cycle 的值与当前值比较(注:这个列表称为列表 2):

  • 检查已经传给子组件用来更新其属性的值,是否与当前将要传入的值相同
  • 检查已经传给当前组件用来更新 DOM 值,是否与当前将要传入的值相同
  • 针对每一个子组件执行相同的检查(注:就是如果子组件还有子组件,子组件会继续执行上面两步的操作,依次递归下去。)

所以我的代码开始时的渲染是没问题,问题出在后面的变更检测,方向有了,就去找为啥吧。

经过排查发现问题是来自这里
image.png
众所周知,pop()是弹出,而angular不是双向绑定的,这就造成视图层的数据发生了改变,而c层的数据没有改变,也就造成了该错误的出现。

[译] 关于 `ExpressionChangedAfterItHasBeenCheckedError` 错误你所需要知道的事情


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK