Angular2变化检测误解 – 用plunker
我正在尝试用Angular2 final完全理解变化检测.
这包括: >处理变更检测策略 我以为我已经对这些概念有了非常明确的概述,但为了确保我的假设正确,我写了一个小傻瓜来测试它们. 我对全球正确的一般理解,但在某些情况下,我有点迷失. 这是羽毛球:Angular2 Change detection playground 关于plunker的快速说明: 很简单: >一个父组件,您可以在其中编辑一个将传递给两个子组件的属性: parent属性可以通过以下任一方式传递给子组件: >更改整个属性对象,并创建一个新对象(“更改obj”按钮)(触发OnPush子项上的更改检测) 对于每个子组件,可以附加或分离ChangeDetector. (“detach()”和“reattach()”按钮) OnPush孩子有一个可以编辑的额外内部属性, 以下是我得到无法解释的行为的场景: Scenario1: >分离OnPush Children和Default Children的更改检测器(单击两个组件上的“detach()”) 预期行为: 目前的行为: Scenario2: >为OnPush组件分离CD 预期行为: 目前的行为: >最后一次,编辑内部值输入并单击更改内部:检测到更改,并更新内部值… 预期行为: 目前的行为: 结论: 根据那些测试,我得出以下结论,这对我来说很奇怪: >具有OnPush策略的组件在输入更改时会“检测到已更改”,即使它们的更改检测器已分离. 您如何看待这些结论? 你能以更好的方式解释这种行为吗? 这是一个错误还是想要的行为?
更新
自Angular 4.1.1(2017-05-04)OnPush应该尊重detach() https://github.com/angular/angular/commit/acf83b9 旧版 关于变更检测如何工作,有很多未记载的内容. 我们应该知道三个主要的changeDetection状态(cdMode): 1)CheckOnce – 0
AppView类 detectChanges(throwOnChange: boolean): void { ... this.detectChangesInternal(throwOnChange); if (this.cdMode === ChangeDetectorStatus.CheckOnce) { this.cdMode = ChangeDetectorStatus.Checked; // <== this line } ... } 2)检查 – 1
3)独立 – 3
以下是使用Detached的地方 AppView类 跳过内容检查 detectContentChildrenChanges(throwOnChange: boolean) { for (var i = 0; i < this.contentChildren.length; ++i) { var child = this.contentChildren[i]; if (child.cdMode === ChangeDetectorStatus.Detached) continue; // <== this line child.detectChanges(throwOnChange); } } 跳过视图检查 detectViewChildrenChanges(throwOnChange: boolean) { for (var i = 0; i < this.viewChildren.length; ++i) { var child = this.viewChildren[i]; if (child.cdMode === ChangeDetectorStatus.Detached) continue; // <== this line child.detectChanges(throwOnChange); } } 跳过将cdMode更改为CheckOnce markPathToRootAsCheckOnce(): void { let c: AppView<any> = this; while (isPresent(c) && c.cdMode !== ChangeDetectorStatus.Detached) { // <== this line if (c.cdMode === ChangeDetectorStatus.Checked) { c.cdMode = ChangeDetectorStatus.CheckOnce; } let parentEl = c.type === ViewType.COMPONENT ? c.declarationAppElement : c.viewContainerElement; c = isPresent(parentEl) ? parentEl.parentView : null; } } 注意:markPathToRootAsCheckOnce在视图的所有事件处理程序中运行: 因此,如果将状态设置为Detached,则不会更改您的视图. 然后OnPush策略如何运作
编译器/ SRC / view_compiler / property_binder.ts const directiveDetectChangesStmt = isOnPushComp ? new o.IfStmt(directiveDetectChangesExpr,[compileElement.appElement.prop('componentView') .callMethod('markAsCheckOnce',[]) .toStmt()]) : directiveDetectChangesExpr.toStmt(); https://github.com/angular/angular/blob/2.1.2/modules/%40angular/compiler/src/view_compiler/property_binder.ts#L193-L197 让我们看看它在你的例子中的样子: 父工厂(AppComponent) 再次回到AppView类: markAsCheckOnce(): void { this.cdMode = ChangeDetectorStatus.CheckOnce; } 情景1
OnPush.cdMode - Detached
AppComponent.detectChanges || / //if (self._OnPush_35_4.detectChangesInInputProps(self,self._el_35,throwOnChange)) { // self._appEl_35.componentView.markAsCheckOnce(); //} OnPush.markAsCheckOnce || / OnPush.cdMode - CheckOnce || / OnPush.detectChanges || / OnPush.cdMode - Checked 因此OnPush.dectectChanges正在解雇. 结论如下:
Scenario2
OnPush.cdMode - Detached
See 3) from scenario 1 => OnPush.cdMode - Checked
如上所述,所有事件处理程序都包含markPathToRootAsCheckOnce.所以: markPathToRootAsCheckOnce || / OnPush.cdMode - CheckOnce || / OnPush.detectChanges || / OnPush.cdMode - Checked 正如您所见,OnPush策略和ChangeDetector管理一个属性 – cdMode
总之,我想说,你似乎是对的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |