关于vue源码flushSchedulerQueue函数queue。sort使用疑惑
先看源码:function flushSchedulerQueue () { currentFlushTimestamp = getNow() flushing = true let watcher, id // Sort queue before flush. // This ensures that: // 1. Components are updated from parent to child. (because parent is always // created before the child) // 2. A component"s user watchers are run before its render watcher (because // user watchers are created before the render watcher) // 3. If a component is destroyed during a parent component"s watcher run, // its watchers can be skipped. queue.sort((a, b) => a.id - b.id) // do not cache length because more watchers might be pushed // as we run existing watchers for (index = 0; index < queue.length; index++) { watcher = queue[index] if (watcher.before) { watcher.before() } id = watcher.id has[id] = null watcher.run() // in dev build, check and stop circular updates. if (process.env.NODE_ENV !== "production" && has[id] != null) { circular[id] = (circular[id] || 0) + 1 if (circular[id] > 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 } } }
这个方法主要是用来执行微任务后回调相关逻辑,queue里缓存了要等待更新的watcher列表,并且将queue按照从小到大进行排序。 queue.sort((a, b) => a.id - b.id)
问题来了,为什么要对queue进行排序?
搜索出来的结果基本上是从英文里翻译过来:组件的更新由父到子;因为父组件的创建过程是先于子的,所以 watcher 的创建也是先父后子,执行顺序也应该保持先父后子。 用户的自定义 watcher 要优先于渲染 watcher 执行;因为用户自定义 watcher 是在渲染 watcher 之前创建的。 如果一个组件在父组件的 watcher 执行期间被销毁,那么它对应的 watcher 执行都可以被跳过,所以父组件的 watcher 应该先执行。
看到这样的回答,有点似懂非懂的感觉,果断用实例来验证下:
断点queue.sort
此时,queue里保存着子组件渲染watcher(称 s)和主渲染watcher(称 p),排序之后的顺序为:[p, s]
其中s这个watcher运行之后,在run函数里边就断掉了!
watcher源文件摘取代码:run () { // 此时的active已经为false if (this.active) { const value = this.get() if ( value !== this.value || // Deep watchers and watchers on Object/Arrays should fire even // when the value is the same, because the value may // have mutated. isObject(value) || this.deep ) { // set new value const oldValue = this.value this.value = value if (this.user) { const info = `callback for watcher "${this.expression}"` invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info) } else { this.cb.call(this.vm, value, oldValue) } } } }
这个active其实是在主渲染watcher执行中被change掉 了,这样可以避免子组件的渲染watcher少执行很多代码啊,节省了很多的性能开销!
以上是个人的一点见解,欢迎留言讨论,喜欢请记得关注哦!
真的如片名一样,有的人,一旦告别就会后会无期对白后会无期我以为电影到最后,会迎来好友的重逢。但结果真的如片名一样,有的人,一旦告别就会后会无期。早知道那是我们最后一次见面,我应该穿得好看点,温柔点,拥抱用力一点,看你久一点,一点就好。离
我很棒,嗯,对一次尝试性的主动出击后,突然发现我做到了。然后,你知道在未来的日子里,我能行。这样的信心时刻,你有过吗?它也许发生在你排除万难顺利完成考试之时在你勇敢表白的那天在你克服心理恐惧终于
吴玉新副教授毫米级颗粒在湍流场中的传热及着火特性能源人都在看,点击右上角加关注创新点通过四风扇对冲的电热实验装置,构建了各向同性湍流流场,可通过改变风扇转速及热功率调节湍流强度及环境温度。基于该实验装置研究了湍流强度对毫米级颗粒
少儿百科科普(十五)七大洲之欧洲小朋友。我是颖宝妈妈,我们的环球旅行又要开始了。今天我们要一路向北来到欧洲。打开欧洲地图,你会发现欧洲和非洲中间包着一大片海洋。这就是著名的地中海陆地中的海洋。这个名字是不是很形象
通州大运河公园头号周刊前天公司要求居家办公,再加周六日这三天等于是放个小长假。有段时间没来通州大运河公园了,今天天气好来看看。北京头条我们去的漕运码头景点,属于大运河北岸。南岸有游乐园,有大看台
青未了黄河故道怀古黄河故道怀古姜宝兵端午节前,应德州市作协之约,参加了全国作家游黄河故道,颂多彩夏津采风活动,昔日夏津因齐晋会盟之要津而得名,今日近百名来自全国各地的作家齐聚黄河故道森林公园感受盛世
韩国安山市政府禁止游客在大阜岛海边露营搭建帐篷本期话题韩国安山市政府禁止游客在大阜岛海边露营搭建帐篷韩国京畿安山市12日表示,继去年之后,今年也将禁止游客在大阜岛海边露营搭建帐篷。这是随着最近新型冠状病毒相关政策放缓游客急剧增
结婚8年后再看聂远才发现,他选择迎娶粉丝秦子越的决定有多聪明聂远演员因戏生情很正常,我对不起王惠选择净身出户,我爱秦子越就要娶她为妻聂远与沙溢不得不说的孽缘2000年,军艺校草沙溢被蹲守在学校门口的导演张子恩发掘,邀请他出演电视剧上错花轿嫁
围棋入门阶段怎么看待输赢?以下3种方法帮助孩子正确认知孩子在围棋启蒙时,从接触吃子开始,第一步面对的就是输赢。大多数孩子的好胜心很强,往往输掉一盘棋后,他们就开始垂头丧气,有的孩子甚至哇哇大哭或是发脾气丢棋子。家长也非常头疼这种局面,
人生变好,是从认知升级开始的文十月(富书作者)乔舒亚萨夫兰说现在所做的决定,都将决定我们成为什么样的人。人生的下半场,有的人,路越走越宽,而有的人,却道阻且长。原因在于人与人之间看待问题的角度和思考问题的方式
做拳王的女人有多不容易,身材火辣,一年被甩23次,如今成为赢家2008年北京奥运会,作为中国拳击队的绝对主力,邹市明心里就下定决心,一定要在家门口为国家争口气。在这种信念的加持下,邹市明的表现异常出色,一改之前的颓势,豪取金牌,卫冕世界冠军。