Vue的异步更新实现原理,web微信开发者工具

}

}

遍历subs里每一个Watcher实例,然后调用实例的update方法,下面我们来看看update是怎么去更新的:

class Watcher {

update() {

//各种情况判断之后

else{

queueWatcher(this)

}

}

}

update执行后又走到了queueWatcher,那就继续去看看queueWatcher干啥了(希望不要继续套娃了:

//queueWatcher 定义在 src/core/observer/scheduler.js

const queue: Array = []

let has: { [key: number]: ?true } = {}

let waiting = false

let flushing = false

let index = 0

export function queueWatcher(watcher: Watcher) {

const id = watcher.id

//根据id是否重复做优化

if(has[id] == null){

has[id] = true

if(!flushing){

queue.push(watcher)

}else{

let i=queue.length - 1

while(i > index && queue[i].id > watcher.id){

i–

}

queue.splice(i + 1, 0, watcher)

}

if(!waiting){

waiting = true

//flushSchedulerQueue函数: Flush both queues and run the watchers

nextTick(flushSchedulerQueue)

}

}

}

这里queue在pushwatcher时是根据idflushing做了一些优化的,并不会每次数据改变都触发watcher的回调,而是把这些watcher先添加到⼀个队列⾥,然后在nextTick后执⾏flushSchedulerQueue

flushSchedulerQueue函数是保存更新事件的queue的一些加工,让更新可以满足Vue更新的生命周期。

这里也解释了为什么for循环不能导致页面更新,因为for是主线程的代码,在一开始执行数据改变就会将它push到queue里,等到for里的代码执行完毕后i的值已经变化为100时,这时vue才走到nextTick(flushSchedulerQueue)这一步。

nextTick源码

接着打开vue2.x的源码,目录core/util/next-tick.js,代码量很小,加上注释才110行,是比较好理解的。

const callbacks = []

let pending = false

export function nextTick (cb?: Function, ctx?: Object) {

let _resolve

callbacks.push(() => {

if (cb) {

try {

cb.call(ctx)

} catch (e) {

handleError(e, ctx, ‘nextTick’)

}

} else if (_resolve) {

_resolve(ctx)

}

})

if (!pending) {

pending = true

timerFunc()

}

首先将传入的回调函数cb(上节的flushSchedulerQueue)压入callbacks数组,最后通过timerFunc函数一次性解决。

let timerFunc

if (typeof Promise !== ‘undefined’ && isNative(Promise)) {

const p = Promise.resolve()

timerFunc = () => {

p.then(flushCallbacks)

if (isIOS) setTimeout(noop)

}

isUsingMicroTask = true

} else if (!isIE && typeof MutationObserver !== ‘undefined’ && (

isNative(MutationObserver) ||

// PhantomJS and iOS 7.x

MutationObserver.toString() === ‘[object MutationObserverConstructor]’

)) {

let counter = 1

const observer = new MutationObserver(flushCallbacks)

const textNode = document.createTextNode(String(counter))

observer.observe(textNode, {

characterData: true

})

timerFunc = () => {

counter = (counter + 1) % 2

textNode.data = String(counter)

}

isUsingMicroTask = true

} else if (typeof setImmediate !== ‘undefined’ && isNative(setImmediate)) {

timerFunc = () => {

setImmediate(flushCallbacks)

}

} else {

timerFunc = () => {

setTimeout(flushCallbacks, 0)

}

}

timerFunc下面一大片if else是在判断不同的设备和不同情况下选用哪种特性去实现异步任务:优先检测是否原生⽀持Promise,不⽀持的话再去检测是否⽀持MutationObserver,如果都不行就只能尝试宏任务实现,首先是setImmediate,这是⼀个⾼版本 IE 和 Edge 才⽀持的特性,如果都不⽀持的话最后就会降级为 setTimeout 0。

这⾥使⽤callbacks⽽不是直接在nextTick中执⾏回调函数的原因是保证在同⼀个 tick 内多次执⾏nextTick,不会开启多个异步任务,⽽把这些异步任务都压成⼀个同步任务,在下⼀个 tick 执⾏完毕。

nextTick使用


nextTick不仅是vue的源码文件,更是vue的一个全局API。下面来看看怎么使用吧。

当设置 vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环tick中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用数据驱动的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。

官网用例:

{{message}}

var vm = new Vue({

el: ‘#example’,

data: {

message: ‘123’

}

})

vm.message = ‘new message’ // 更改数据

vm.$el.textContent === ‘new message’ // false

Vue.nextTick(function () {

vm.$el.textContent === ‘new message’ // true

})

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

资料领取方式:戳这里前往免费领取

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值