-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
浅析Vue 中的patch和diff(上) #2
Comments
数据更新那部分流程讲得很棒!学习了~ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
疑问
1.当我修改了属性值时,vdom立即进行diff,重新渲染视图了吗?
2.如果1是对的,那重复修改,性能岂不是很差?如果不是,1是如何实现的?
3.我们的nextTick 具体的实现是怎样的?什么时候需要用到它?
4.vdom diff的过程是怎样的?
梗概
关于vue数据更新渲染的几个知识点,先列一下:
数据的更新是实时的,但是渲染是异步的。
一旦数据变化,会把在同一个事件循环event loop中的观察到的watcher 推入一个队列(相同watcher实例不会重复推入)
DOM并不是马上更新视图的(想想也不可能,改动一次数据更新一次视图,肯定都是批量操作DOM的),vue 中的nextTick 用到了MicroTask和MacroTask,这需要我们去了解event loop(推荐先阅读下:Tasks, microtasks, queues and schedules
)
整个script是一个主任务, setTimeout 是一个macroTask, promise的回调是microtask, 顺序是:
主任务Task —> Task为空开始 microTask (全部执行完)—> UI渲染 —> 取一个macroTask执行
所以dom diff 这个过程是在microtask中去处理的(也有的是强制走macrotask, 本例子走microtask)
哪些会走macrotask 哪些会走microtask,为啥要区分,会写在拓展那一小节
例子
接下来,所有的讲解都会围绕下面这个例子
入口
当
vm._update(vm._render(), hydrating)
经过上一次分享,我们知道通过
vm._render()
方法,我们会获得我们的vdom; 接下去我们进入_update方法;我们看下内部的细节。初始进入patch
数据更新时
假设我们的数据是
{a:1, b:1}
更新为了{a:2, b:3}
, 我们下面看下细节data.a执行完以后,开始走data.b, 流程都一样,只是当我们遇到watcher的update时有些区别
然后进入
this.$nextTick
方法接下去,就到了我们之前讲到的,主script执行完了开始执行microTask, 进入flushSchedulerQueue方法。(tips: 推荐阅读Tasks, microtasks, queues and schedules更好地了解EventLoop)
总结
这一篇blog主要是为了让大家清楚
拓展
思考1:不用nextTick
如果很好地理解了micoTask 与 macroTask之间的关系,那么也能很清楚的理解假设我们写成下面这样, 为什么不行了,自己试试喽!下一篇,会细致讲解vdom diff 的过程~
思考2: 如果都用MicroTask有什么问题?
看下这个issue, @click would trigger event other vnode @click event. #6566
贴一下代码,vue的版本是2.4.2,在此版本下当你点击了‘expand is true’以后,expand click 和 off click都打印出来了,countA与countB都变成了1,文案还是expand is true
尤大在这个issue下面给了回答,引一下:
大致原因是:
<i>
标签的点击动作触发了第一次nextTick(microTask), 然后我们得到了新的vdom并进行了渲染;microTask先于冒泡这个task,在microTask生成新dom的过程中,外层div添加了listener; 渲染完成后,冒泡触发了新的listener,所以又进入了新的cb。所以在Vue2.5版本中你会看到event handler使用了macroTask进行包裹参考资料
1.vue2.0 正确理解Vue.nextTick()的用途 http://www.cnblogs.com/minigrasshopper/p/7879545.html
2.从event loop规范探究javaScript异步及浏览器更新渲染时机 aooy/blog#5
3.Promise的队列与setTimeout的队列有何关联?https://www.zhihu.com/question/36972010/answer/71338002
4.JavaScript 运行机制详解:再谈Event Loop http://www.ruanyifeng.com/blog/2014/10/event-loop.html
5.Vue源码详解之nextTick:MutationObserver只是浮云,microtask才是核心!Ma63d/vue-analysis#6
https://chuckliu.me/#!/posts/58bd08a2b5187d2fb51c04f9
6.Tasks, microtasks, queues and schedules https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
7.@click would trigger event other vnode @click event. #6566 vuejs/vue#6566
The text was updated successfully, but these errors were encountered: