14

大きな ng1 (V1.5.9) アプリ (ui-router を使用) 内でいくつかの新しい ng2 (V2.2.4) コンポーネントを使用するために ng-upgrade を使用するアプリケーションでは、現在、非常に奇妙な変更検出の問題が発生しています。私が知る限り、これは ng2 のアップグレードで導入されましたが、残念ながら現在は簡単に確認できません。

私はこのコンポーネントを持っているだけの最小限の例に減らしました:

@Component({
    selector:'my-ng2-demo',
    template: '<div>{{status}}</div>'
})
export class MyNg2Demo implements OnDestroy {
    public status:boolean = true;
    private interval:any;

    constructor() {
        this.interval = setInterval(() => {
            this.status = !this.status;
            console.log('status: ' + this.status);
        }, 2000);
    }

    ngOnDestroy():void {
        clearInterval(this.interval);
    }

}

そのコンポーネントは upgrade-adapter でアップグレードされ、モジュールの entry-component として登録されます。

コンポーネントは、次のように ng1 コントローラーのテンプレートで使用されます。

<my-ng2-demo></my-ng2-demo>

ブラウザーを開いてそのページ (ng1 コントローラーのルート) に直接移動すると、すべてが期待どおりに機能します。UI は true/false を 2 秒ごとに交互に表示します。

ただし、移動してからページに戻ると(いくつかの異なるルートにアクセスすると)、突然変更検出が機能しないようです。表示される値は約 5 ~ 6 秒ごとに交互に変化し、非常にランダムに見えますが、コンソールにはまだ期待値が表示されています。

コンポーネントのコンストラクターを次のように変更すると:

constructor(private zone: NgZone) {
    this.interval = setInterval(() => {
        zone.run(() => {
            this.status = !this.status;
            console.log('status: ' + this.status);
        });
    }, 2000);
}

突然再び機能します。

実際のアプリで見られる動作ははるかに複雑であるため、明らかにこれは実行可能な解決策ではありません (zone.runおそらく数十の場所に追加する必要があり、これは維持できません)。

これを何時間もデバッグしましたが、何が起こっているのかわかりません。Chrome の JavaScript プロファイラーでは、基本的に、何も起こらない 5 ~ 6 秒間、ページがほぼずっとアイドル状態になっていることがわかります。

プロファイラー これはそのデモ コンポーネントのスクリーンショットではありませんが (ただし、基本的には同じように見えます)、最初にテストしていたタブ コンポーネントのプロファイリングからのものです (タブの切り替えにかかった時間はその間に何も表示されません)。

アップデート:

もう少し実験した後、私が非常に驚くべきことを見つけたのは、ステータス変更コードを呼び出しに入れる代わりに、へのzone.run呼び出しを追加することApplicationRef.tick() です (たとえば、ここで説明したように: https://stackoverflow.com/a/34829089/ 1335619 ) また、まったく機能しません。完全なアプリケーション変更検出を強制しても何も起こらない理由はわかりませんが、ゾーン実行呼び出しは何とか機能します。

動作しない tick 呼び出しのコード例:

constructor(private applicationRef:ApplicationRef) {
    this.interval = setInterval(() => {
        this.status = !this.status;
        console.log('status: ' + this.status);
        applicationRef.tick();
    }, 2000);
}
4

1 に答える 1