вот что происходит;
в режиме разработки происходят два последовательных цикла CD, как описано в Соответствующие операции по обнаружению изменений этой статьи;
Работающее приложение Angular представляет собой дерево компонентов. Во время обнаружения изменений Angular выполняет проверки для каждого компонента, которые состоят из следующих операций, выполняемых в указанном порядке:
- обновить связанные свойства для всех дочерних компонентов/директив
- вызывать хуки жизненного цикла ngOnInit, OnChanges и ngDoCheck для всех дочерних компонентов/директив
- обновить DOM для текущего компонента
- запустить обнаружение изменений для дочернего компонента
- вызвать крючок жизненного цикла ngAfterViewInit для всех дочерних компонентов/директив
- после того, как вы нажмете кнопку «Добавить», когда обратный вызов завершает выполнение, начинается обнаружение изменений.
comp
содержит 1 элемент
- во время первого цикла CD; DOM обновляется на шаге 3. элементы в
comp
добавляются в DOM, а {{ count.length }}
проецируются в DOM как 0
@ViewChildren('comp') test: QueryList<ElementRef>
обновляется непосредственно перед шагом 5. test: QueryList
содержит 1 элемент
QueryList.changes
observable генерируется одновременно с установленным ViewChildren
запросом, непосредственно перед шагом 5. this.count.push(this.test.length)
выполняется, а count.length
становится равным 1.
ngAfterViewChecked
выполняется, и первый компакт-диск (соответствующая часть нашего расследования) заканчивается
- Начинается 2-й цикл CD. во время этого цикла angular проверяет предыдущие значения 1-го цикла CD с текущими значениями.
- Во время этой проверки он обнаруживает, что
{{ count.length }}
был спроецирован в DOM как 0, но теперь count.length
равен 1. В этот момент возникает исключение.
Чтобы объяснить больше; изменение {{ count.length }}
на {{ count }}
не вызывает ошибку, поскольку ссылка на объект не изменилась.
Сходным образом; изменение {{ count.length }}
на {{ comps.length }}
также не вызывает ошибки, потому что comps.length
также было 1 до начала 1-го цикла компакт-диска.
Я также создал демонстрацию, которая печатает соответствующие шаги в течение жизненного цикла компонента, связанного с нашим исследованием. Вы можете видеть, что исключение выдается до начала 4-го цикла CD. (1-й и 2-й циклы CD происходят до нажатия кнопки, поэтому в демо-версии следует соблюдать 3-й и 4-й циклы CD). Также обратите внимание на точку, где QueryList.changes
выдает значение.
https://stackblitz.com/edit/angular-tmcttm
Наконец, как вы сказали, решение этой конкретной проблемы состоит в том, чтобы добавить микрозадачу в очередь, изменив эту строку
this.count.push(this.test.length);
в это
setTimeout(_ => this.count.push(this.test.length));
person
ysf
schedule
14.06.2019
ChangeDetectorRef.detectChanges
. - person ConnorsFan   schedule 15.06.2019