- URL 中 hash 值只是
客户端
的一种状态
,也就是说当向服务器端发出请求时
,hash 部分不会被发送
;
- hash 值的
改变
,都会在浏览器的访问历史
中增加
一个记录
。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
- computed是
计算属性
,也就是计算值,它更多用于计算值的场景
- computed具有
缓存性
,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
- computed适用于计算比较消耗性能的计算场景
- 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察
props
$emit
或者本组件
的值,当数据变化时来执行回调进行后续操作
- 无缓存性,页面重新渲染时值
不变化
也会执行
- 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
- 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化
// 给组件绑定一个事件,有两种绑定方法
这里假设运行环境中Promise对象是完全支持的,那么使用setTimeout是宏队列在最后执行这个是没有异议的,但是使用$nextTick
方法以及自行定义的Promise实例是有执行顺序的问题的,虽然都是微队列任务,但是在Vue中具体实现的原因导致了执行顺序可能会有所不同,首先直接看一下$nextTick
方法的源码,关键地方添加了注释,请注意这是Vue2.4.2版本的源码,在后期$nextTick
方法可能有所变更。
var pending = false; // 标识,用以判断在某个事件循环中是否为第一次加入,第一次加入的时候才触发异步执行的队列挂载 var timerFunc; // 以何种方法执行挂载异步执行队列,这里假设Promise是完全支持的 //判断在当前事件循环中是否为第一次加入,若是第一次加入则置标识为true并执行timerFunc函数用以挂载执行队列到Promise //
这个标识在执行队列中的任务将要执行时便置为false并创建执行队列的副本去运行执行队列中的任务,参见nextTickHandler函数的实现 // 在当前事件循环中置标识true并挂载,然后再次调用nextTick方法时只是将任务加入到执行队列中,直到挂载的异步任务触发,便置标识为false然后执行任务,再次调用nextTick方法时就是同样的执行方式然后不断如此往复
回到刚才提出的问题上,在更新DOM操作时会先触发$nextTick
方法的回调,解决这个问题的关键在于谁先将异步任务挂载到Promise对象上。
console.log(2))语句的挂载,当执行微任务队列中的任务时,首先会执行第一个挂载到Promise的任务,此时这个任务是运行执行队列,这个队列中有两个方法,首先会运行flushSchedulerQueue方法去触发组件的DOM渲染操作,然后再执行console.log(3),然后执行第二个微队列的任务也就是() =>
接下来对于没有数据更新的updateMsgTest按钮触发的方法进行debug,断点设置在同样的位置,此时没有数据更新,那么第一次触发$nextTic
k方法的是自行定义的回调函数,那么此时$nextTick
方法的执行队列才会被挂载到Promise对象上,很显然在此之前自行定义的输出2的Promise回调已经被挂载,那么对于这个按钮绑定的方法的执行流程便是首先执行console.log(2),然后执行$nextTick
方法闭包的执行队列,此时执行队列中只有一个回调函数console.log(3),此时微任务队列清空,然后再去宏任务队列执行console.log(1)。
简单来说就是谁先挂载Promise对象的问题,在调用$nextTick
方法时就会将其闭包内部维护的执行队列挂载到Promise对象,在数据更新时Vue内部首先就会执行$nextTick
方法,之后便将执行队列挂载到了Promise对象上,其实在明白Js的Event
Loop模型后,将数据更新也看做一个$nextTick
方法的调用,并且明白$nextTick
方法会一次性执行所有推入的回调,就可以明白其执行顺序的问题了,下面是一个关于$nextTick方法的最小化的DEMO。