记一次解决错误ExpressionChangedAfterItHasBeenCheckedError

34次阅读

共计 1021 个字符,预计需要花费 3 分钟才能阅读完成。

问题的出现

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

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

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

为何会出现

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

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

angular 的渲染流程

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

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

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

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

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

问题所在

经过排查发现问题是来自这里

众所周知,pop()是弹出,而 angular 不是双向绑定的,这就造成视图层的数据发生了改变,而 c 层的数据没有改变,也就造成了该错误的出现。

参考文章

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

正文完
 0