Scheduler: батчинг обновлений, flush pre/post/sync

↑ 7.1 Vue под капотом · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Объясняет, почему DOM обновляется не сразу и зачем нужен nextTick.

Батчинг

Несколько изменений состояния подряд не вызывают несколько рендеров. Vue ставит компонент в очередь и обновляет один раз за тик (микрозадача).

const count = ref(0)
count.value++
count.value++
count.value++      // рендер будет один
await nextTick()   // DOM уже обновлён

Очереди

  1. pre — колбэки watch с flush: 'pre' (по умолчанию), до рендера компонента;
  2. render — обновление компонентов (родитель раньше ребёнка, отсортировано по id);
  3. post — flush: 'post', onMounted/onUpdated: DOM уже готов;
  4. sync — flush: 'sync', срабатывает мгновенно при изменении.
watch(source, cb)                        // pre
watch(source, cb, { flush: 'post' })     // после обновления DOM
watch(source, cb, { flush: 'sync' })     // синхронно (осторожно)
watchPostEffect(() => { /* DOM готов */ })

nextTick

Возвращает промис, который разрешается после текущего flush. Нужен, когда после изменения состояния надо прочитать обновлённый DOM (размеры, фокус).

Нюансы

  • sync может вызывать каскады и падение производительности;
  • обновление родителя, не затрагивающее props ребёнка, не перерисовывает ребёнка;
  • рекурсивные обновления ограничены (лимит 100) с предупреждением.

Вопросы с ответами