什么是响应式数据:数据变了,视图能更新,反之视图更新,数据要不要更新,不归响应式数据管。
Vue 在内部实现了一个最核心的definereactive方法,借助了Object.defineProperty,核心就是劫持属性(只会劫持已经存在的属性),把所有的属性,重新的添加了 getter 和 setter,因此在用户取值和设置值的时候,可以进行一些操作。
Vue 在初始化的时候会进行挂载$mount操作,会进行编译操作,最终会走到render function,当组件进行渲染时会去取值,取值getter时,调用dep.depend()收集这个 watcher,存放在Dep中,当我们去更改值setter,调用dep.notify()去通知这个 watcher 去更新,实际上 watcher 中存放的就是组件的update函数.更新的时候,就会走到虚拟 dom 相关的方法。
模板编译原理实际上就是 将 template 转换成 render 函数,大致可分为以下三步:
function mergeHook(parentVal, childVal) {
const res = childVal // 儿子有
? parentVal
? parentVal.concat(childVal) // 父亲也有,就是合并
: Array.isArray(childVal) // 儿子是数组
? childVal
: [childVal] // 不是数组包装成数组
: parentVal;
return res ? dedupeHooks(res) : res;
}
当用户修改了数据后并不会马上更新视图,更新 DOM 时是异步执行的,只要侦听到数据变化,Vue 将开启一个任务队列,并缓冲同一时间循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。而 $nextTick 中的方法会被放到更新队列的后面,在下次 DOM 更新循环结束之后执⾏延迟回调,视图需要等队列中所有任务完成之后,再统一进行更新。在修改数据之后使⽤ $nextTick,则可以在回调中获取更新后的 DOM。
Vue 在内部对异步队列尝试使用原生的 Promise.then(微任务)、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0)(宏任务)代替。
因此 Vue.set 实际上就是两个方法的集合,target.splice(key,1,val) 和 defineReactive(ob.value,key,val),
是什么:Virtual DOM 就是用 js 对象来描述真实 DOM 结构,是对真实 DOM 的抽象。
为什么:由于直接操作 DOM 性能低,但是 js 层的操作效率高,可以将 DOM 操作转化成对象操作,最终通过 diff 算法比对新旧 vdom 的差异进行更新 DOM(减少了对真实 DOM 的操作)。
边操作 dom 边获取视图,每次操作 dom 都可能会引起 dom 的回流和重绘,导致性能不高,有了 vdom 就可以把所有的操作都放在 vdom 上,最终把更新和一系列的逻辑批量的同步到真实 dom 上,
好处:虚拟 DOM 不依赖真实平台环境从而也可以实现跨平台。比如 nodejs 就没有 Dom,想要实现 SSR 就需要借助 Vdom
Vue 的 diff 算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式 + 双指针的方式进行比较(双指针分别指向新旧的结尾)。
diff 的复杂度 是 O(n),当一方子元素的头尾相等时,结束循环,(因为同层比较,内部只有一层循环).子元素嵌套时,递归同层比较
如果不能匹配到的话,就会根据当前的老的索引 key 创建一个映射表,拿新的去里面找,如果能找到就复用,找不到就创建新的,最终把老的多余的删掉,
一个属性对应一个 dep, 一个 dep 对应多个 watcher(数据多页面共享)
一个组件对应一个 watcher,一个 watcher 可以对应多个 dep(多个属性)
观察者模式: dep 收集 watcher,变化时一次通知,watcher 是观察者,dep 是被观察者
dep 用来收集渲染逻辑(watcher),watcher 中存放的是组件的 update 函数。数据变化通知 dep 中的 watcher 去执行对应的 update 方法
页面重新渲染逻辑:只有当页面模板中用到的数据(就是写在 render 中的数据) 发生改变时,才会调用 update 方法
开启一个异步队列并将更新的 watcher 去重,将用户的$nextTick 和内部的更新逻辑, 合并为一个 Promise.then,依次执行(多个 nextTick 是一个 promise.then)
nextTick 用一个异步任务,将多个方法维持一个队列里,执行时机遵循 js 的 eventloop 机制,具体的执行时机 ,要看底层用的是那个方法,因为 vue 考虑了浏览器的兼容性,vue 中对 nextTick 做了很多兼容性处理,promise 微任务 > MutationObserver(h5 的 api 微任务) > setImmediate > setTimeout
keep-alive 组件是一个抽象组件, 也是一个虚拟组件, 不会被记录到父子组件关系当中,一般用在路由组件的外层, 主要为了缓存组件, 为频繁挂载销毁,提供缓存功能节约性能,
render
获取 keep-alive 中的所有子组件,获取插槽中的第一个,根据组件的名称, 判断 include 和 exclude, 拿到后把组件的实例缓存起来
拿到组件的 key 用来做缓存,如果有缓存 获取缓存的实例,ABA,=>shift 以后再 push
缓存组件 会缓存子组件,缓存的是父节点的 el, 其中包含着所有子组件渲染后完整的结果。
第一次渲染完毕后,会把虚拟节点进行标记直接返回一个组件,keep-alive 最终渲染的结果就是第一个子组件
mounted
缓存中存放了 {组件的 key : 组件的实例},复用的时候,直接使用缓存中,组件的实例
如果超过最大限制 需要删除第一个,在增加最新的,遵循 LRU 原则(Least Recently Used 即最近最久未使用的)
组件更新
每次切换组件,都会进行组件的初始化流程 init 方法,第一次组件渲染时,会在组件虚拟节点上挂载 componentIntance 属性和 keepalive 标记
更新时会再次调用 init 方法,此时会判断虚拟节点的属性和 keepalive 标记,进行 prepatch 方法,对会组件插槽中的内容进行比较。
会判断组件是否需要进行强制更新,会比较新老节点,去执行当前实例的强制更新方法,vm.$forceUpdate ,实际走的就是 keep-alive 的 render()
来自:https://www.cnblogs.com/echoyya/archive/2022/09/26/16726541.html
在日常 Coding 中,码农们肯定少不了对数组的操作,其中很常用的一个操作就是对数组进行遍历,查看数组中的元素,然后一顿操作猛如虎。今天暂且简单地说说在 JavaScript 中 forEach。
克隆项目代码到本地(git应该都要会哈,现在源码几乎都会放github上,会git才方便,不会的可以自学一下哦,不会的也没关系,gitHub上也提供直接下载的链接);打开微信开发者工具;
随着这些模块逐渐完善, Nodejs 在服务端的使用场景也越来越丰富,如果你仅仅是因为JS 这个后缀而注意到它的话, 那么我希望你能暂停脚步,好好了解一下这门年轻的语言,相信它会给你带来惊喜
在 Vue 内部,有一段这样的代码:上面5个函数的作用是在Vue的原型上面挂载方法。initMixin 函数;可以看到在 initMixin 方法中,实现了一系列的初始化操作,包括生命周期流程以及响应式系统流程的启动
nextTick的使用:vue中dom的更像并不是实时的,当数据改变后,vue会把渲染watcher添加到异步队列,异步执行,同步代码执行完成后再统一修改dom,我们看下面的代码。
React更新的方式有三种:(1)ReactDOM.render() || hydrate(ReactDOMServer渲染)(2)setState(3)forceUpdate;接下来,我们就来看下ReactDOM.render()源码
在React中,为防止某个update因为优先级的原因一直被打断而未能执行。React会设置一个ExpirationTime,当时间到了ExpirationTime的时候,如果某个update还未执行的话,React将会强制执行该update,这就是ExpirationTime的作用。
算法对于前端工程师来说总有一层神秘色彩,这篇文章通过解读V8源码,带你探索 Array.prototype.sort 函数下的算法实现。来,先把你用过的和听说过的排序算法都列出来:
extend是jQuery中一个比较核心的代码,如果有查看jQuery的源码的话,就会发现jQuery在多处调用了extend方法。作用:对任意对象进行扩;’扩展某个实例对象
state也就是vuex里的值,也即是整个vuex的状态,而strict和state的设置有关,如果设置strict为true,那么不能直接修改state里的值,只能通过mutation来设置
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!