shuffle
Fisher-Yates
1 | var source_array = [1,2,3,4,5] |
两个有序数组合并
1 | var arr1 = [2, 7, 15, 23] |
Fisher-Yates
1 | var source_array = [1,2,3,4,5] |
1 | var arr1 = [2, 7, 15, 23] |
这个操作是在initData中Observer实例初始化时通过defineReactive函数实现,同时每个属性对应一个dep实例。同时Watcher被实例化,每个组件都有相应的Watcher实例。
1 | // 在初始化属性时,初始化观察者,并且遍历属性,使其成为响应属性 |
当render函数运行时,getter将被触发,此时watcher收集依赖。【将wathcer添加到dep的subscribes中】
1 | // 渲染函数运行时,触发各个属性的getter |
属性被赋值时,值变更触发依赖更新:
1 | // 属性发生变更时,触发对应属性的setter |
源码注释👹
Observer class that are attached to each observed object. Once attached, the observer converts target object's property keys into getter/setters that collect dependencies and dispatches updates.
解读
观察者,会为目标对象上的各个属性添加getter/setters
, 用于收集依赖,触发更新。
1 | value: any; |
1 | observe(data, true) |
源码中的注释👹
A watcher parses an expression, collects dependencies, and fires callback when the expression value changes. This is used for both the $watch() api and directives.
侦听器,解析一个表达式,并且收集过程中的依赖,当表达式的值发生变化时,触发回调函数。
1 | vm: Component, |
1 | new Watcher(vm, expOrFn, cb, opitons) |
源码注释👹
A dep is an observable that can have multiple directives subscribing to it. Sub array to save which properties depend on it
解读
用于记录订阅者(Sub数组),并为每个vue实例的侦听器添加属性依赖
1 | static target: ?Watcher, |
1 | new Dep() |
流程
1 | watcher.update() |
关于queueWatcher
源码注释👹
Push a watcher into the watcher queue. Jobs with duplicate IDs will be skipped unless it's pushed when the queue is being flushed.
解读
将监听器放入队列尾部。重复的任务将会被跳过。
源码注释👹
Flush both queues and run the watchers.
解读
清空队列并且运行监听器的回调函数
文件路径:~/github/vuejs/vue/src/core/vdom/patch.js
笔记:
这个文件中会创建一个patch的函数,传入nodeOps以及modules
关于nodeOps
关于modules
其中,modules中包含了baseModules以及platformModules;baseModules中包含了ref及directives的钩子函数,分别为create, update, destory
,这些函数会在vnode对应的周期"create", "activate", "update", "remove", "destroy"
中被调用。
patch函数在vue进行update时被调用
文件路径:~/github/vuejs/vue/src/core/vdom/patch.js
条件一:isUndef(oldVnode)
源码注释👹empty mount (likely as component), create new root element
解读:当未创建vnode时,创建一个新的vnode作为根节点
条件二:!isRealElement && sameVnode
源码注释👹patch existing root node
解读:如果不是一个真实的dom节点,则对根节点开始进行patchVnode的流程
流程patchVnode
条件二:isRealElement || sameVnode
解读:不是相同的节点,则创建一个新的dom节点,并把老的节点移除(如果是真实元素的话,会根据这个节点再创建vnode)
流程create new Elm
➡️update parent placeholder node element, recursively
➡️destroy old node
如果两个vnode引用是相同的,会直接退出
data.hook.prepatch ➡️
directive.cbs.update
data.hook.update ➡️
情况1, vnode.text -> setTextContent
!vnode.text
情况2, oldCh && ch -> updateChildren
情况3, ch -> addVnodes
情况4, oldCh -> removeVnodes
情况1,sameVnode(oldStartVnode, newStartVnode),不需要移动
情况2,sameVnode(oldEndVnode, newEndVnode),不需要移动
情况3,sameVnode(oldStartVnode, newEndVnode),当前节点右移
情况4,sameVnode(oldEndVnode, newStartVnode),当前节点右移
情况5-1,有key的情况 sameVnode(vnodeToMove, newStartVnode),当前节点左移
情况5-2,没有key的情况 创建一个新的节点
当结束上述比对时
如果oldVnode先遍历完,此时newStarIndex到newEndIndex是新增的节点,则addVnodes
如果newVnode先遍历完,此时oldStarIndex到oldEndIndex是需要删除的节点,则removeVnodes
情况1,如果vnode.elm已经存在,说明该vnode在先前的render中,已经使用,而在这里作为一个新的节点来使用,需要克隆一个新的vnode,不影响之前的节点
如果是组件,则创建对应组件,并退出