С помощью @David я нашел ответ.
Перво-наперво, Rx Js в любом случае не обернут зоной, но встроенные функции asyn c (как setTimer/Iterval
, fetch
api, XHR
, DOM events
). Поскольку операторы Rx Js timer / delay (...) используют собственные функции asyn c, это приводит к тому, что они также обрабатываются в контексте зоны.
Вот как выглядит стек вызовов, когда мы находимся в операторе Rx tap
Вы можете видеть, что часть Rx идет после Angular / Zone .
Angular в свою очередь использует зону для вызова функции tick()
всякий раз, когда выполняется обратный вызов asyn c. Метод Tick
идет вниз от компонента root и ищет отмеченные для проверки представления.
Я помещаю точку останова в функцию тика, он вызывается после выполнения нашего обратного вызова
Итак, что происходит в первом случае, когда мы используем async pipe
в шаблоне.
- Asyn c обратный вызов обрабатывается оператором asyn c pipe, а функция markForCheck () вызывается
- Как мы знаем, markForCheck отмечает текущие и родительские представления вплоть до RootComponent для проверка
- После выполнения обратного вызова с шага 1 вызывается
tick()
. Что, наконец, проверит представление и обновит его
И почти то же самое происходит во втором случае, когда мы вызываем markForCheck
внутри оператора Rx Js. Мы делаем то же самое, что и async pipe
, и поскольку наш обратный вызов также заключен в зону, у нас есть тот же процесс, который будет выполняться после выполнения обратного вызова.
Если вы не вызовете markForCheck в своем asyn c обратный вызов, но вызов функции тика, обновление не будет. Стоит упомянуть, что если вы вызовете detectChanges (), обновление будет выполнено, несмотря на то, что функция markForCheck не была вызвана. Вот пример на stackblitz Это связано с тем, что DetechChanges из ChangeDetectorRef игнорирует флаг markForCheck и обнаруживает изменения для Component и всех его дочерних элементов. Более подробная информация содержится в этой статье
Этот метод запускает обнаружение изменений для текущего представления компонента независимо от его состояния