浏览器事件循环与vue nextTicket的实现(2)

export function queueWatcher (watcher: Watcher) { const id = watcher.id if (has[id] == null) { has[id] = true if (!flushing) { 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 nextTick(flushSchedulerQueue) } } }

queueWatcher做了在一个tick内的多个更新收集。

具体逻辑我们在这就不专门讨论了(有兴趣的可以去查阅vue的观察者模式),逻辑上就是调用了nextTick方法

所以vue的数据更新是一个异步的过程。

那么我们在vue逻辑中,当想获取刚刚渲染的dom节点时我们应该这么写

你肯定会说应该这么写

getData(res).then(()=>{ this.xxx = res.data this.$nextTick(() => { // 这里我们可以获取变化后的 DOM }) })

没错,确实应该这么写。

那么问题来了~

前面不是说UI Render是在microTask都执行完之后才进行么。

而通过对vue的$nextTick分析,它实际是用promise包装的,属于microTask。

在getData.then中,执行了this.xxx= res.data,它实际也是通过wather调用$nextTick

随后,又执行了一个$nextTick

按理说目前还处在同一个事件循环,而且还没有进行UI Render,怎么在$nextTick就能拿到刚渲染的dom呢?

我之前被这个问题困扰了很久,最终通过写test用例发现,原来UI Render这块我理解错了

UI render理解

之前一直以为新的dom节点必须等UI Render之后渲染才能获取到,然而并不是这样的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/63db3ec9dafa14741ce968a85091039c.html