Vue 子组件渲染次数与父组件 props 和子组件数据变化的关系?-灵析社区

JayCoder

在Vue的源码中,当响应式数据发现改变的时候并不会立刻更新页面,而是执行执行queueWatcher函数,而这个函数内部维护着一个队列,而需要执行更新的组件会被推入到这个队列中,如果你在一个事件循环多次向这个队列中push同一个组件,它只会push一次,因为它每次push的时候都会拿你正在push的组件的id去跟队列中的组件的id比较,如果存在就不再push。Vue会把队列通过nextTick来执行,而nextTick也不是立刻执行的,它内部是以Promise,mutationObserver,setImmediate,setTimeout其中一个来执行,优先级就是上面的排列顺序,所以它就变成了一个异步任务。因此子组件只会更新一次。 Vue视图更新源码分析如下: /** *将观察程序推入观察程序队列。 *ID重复的作业将被跳过,除非 *在刷新队列时推送。 */ export function queueWatcher(watcher: Watcher) { // 首先获取当前 watcher 的 id const id = watcher.id // 判断这个 watcher 是否已经存在,因为 Vue 并不是在数据发生变化之后立刻更新视图 // 而是收集起来的,因此在上一次没有更新视图之前,即使数据发生改变也无需再添加,因为 // watcher 更新视图的时候使用的数据依然是最新的数据 if (has[id] != null) { // 已经存在就不再收集 return } if (watcher === Dep.target && watcher.noRecurse) { return } has[id] = true if (!flushing) { // 否则把 watcher 放到一个队列中,在下一次事件循环的时候再一次性更新视图; queue.push(watcher) } else { // if already flushing, splice the watcher based on its id // if already past its id, it will be run next immediately. let i = queue.length - 1 while (i > index && queue[i].id > watcher.id) { i-- } queue.splice(i + 1, 0, watcher) } // queue the flush // 接着就开始执行渲染 if (!waiting) { waiting = true if (__DEV__ && !config.async) { flushSchedulerQueue() return } // 执行渲染,可以看到它调用的就是 nextTick 方法; // flushSchedulerQueue 就是刷新页面的 nextTick(flushSchedulerQueue) } } function flushSchedulerQueue() { currentFlushTimestamp = getNow() flushing = true let watcher, id //刷新前对队列进行排序。 //这样可以确保: //1。组件从父级更新到子级。(因为父母总是 //在子项之前创建) //2。组件的用户观察程序在其渲染观察程序之前运行(因为 //用户观察程序是在渲染观察程序之前创建的) //3。如果组件在父组件的观察程序运行期间被破坏, //它的观察者可以被跳过。 queue.sort(sortCompareFn) //不要缓存长度,因为可能会推送更多的观察者 //当我们运行现有的观察程序时 for (index = 0; index MAX_UPDATE_COUNT) { warn( 'You may have an infinite update loop ' + (watcher.user ? `in watcher with expression "${watcher.expression}"` : `in a component render function.`), watcher.vm ) break } } }

阅读量:1

点赞量:0

问AI