腾讯企业邮箱登录登录入口,seo服务外包费用,广州移动端网站建设,网站网页设计工作内容#x1f3ac; 江城开朗的豌豆#xff1a;个人主页 #x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 #x1f4dd; 个人网站 :《 江城开朗的豌豆#x1fadb; 》
⛺️ 生活的理想#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 #x1f4d8; 文章引言
一、N… 江城开朗的豌豆个人主页 个人专栏 :《 VUE 》 《 javaScript 》 个人网站 :《 江城开朗的豌豆 》
⛺️ 生活的理想就是为了理想的生活 ! 目录 ⭐ 专栏简介 文章引言
一、NextTick是什么
为什么要有nexttick
二、使用场景
三、实现原理
⭐ 写在最后 ⭐ 专栏简介 欢迎来到前端入门之旅这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念并提供实际案例和练习让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具我们都将为你提供丰富的内容和实用技巧帮助你更好地理解并运用前端开发中的各种技术。 同时我们也会关注最新的前端趋势和发展动态。随着Web技术的不断演进前端开发也在不断推陈出新。我们会及时介绍最新的前端框架、工具和技术使你能够站在前沿与时俱进。通过掌握最新的前端技术你将能够在竞争激烈的Web开发领域中有更大的竞争力。 文章引言
一、NextTick是什么
官方对其的定义 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法获取更新后的 DOM 什么意思呢
我们可以理解成Vue 在更新 DOM 时是异步执行的。当数据发生变化Vue将开启一个异步更新队列视图需要等队列中所有数据变化完成之后再统一进行更新
举例一下
Html结构
div idapp {{ message }} /div
构建一个vue实例
const vm new Vue({el: #app,data: {message: 原始值}
})
修改message
this.message 修改后的值1
this.message 修改后的值2
this.message 修改后的值3
这时候想获取页面最新的DOM节点却发现获取到的是旧值
console.log(vm.$el.textContent) // 原始值
这是因为message数据在发现变化的时候vue并不会立刻去更新Dom而是将修改数据的操作放在了一个异步操作队列中
如果我们一直修改相同数据异步操作队列还会进行去重
等待同一事件循环中的所有数据变化完成之后会将队列中的事件拿来进行处理进行DOM的更新
为什么要有nexttick
举个例子 {{num}}
for(let i0; i100000; i){num i
} 如果没有 nextTick 更新机制那么 num 每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图)有了nextTick机制只需要更新一次所以nextTick本质是一种优化策略
二、使用场景
如果想要在修改数据后立刻得到更新后的DOM结构可以使用Vue.nextTick()
第一个参数为回调函数可以获取最近的DOM结构
第二个参数为执行函数上下文
// 修改数据
vm.message 修改后的值
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {// DOM 更新了console.log(vm.$el.textContent) // 修改后的值
})
组件内使用 vm.$nextTick() 实例方法只需要通过this.$nextTick()并且回调函数中的 this 将自动绑定到当前的 Vue 实例上
this.message 修改后的值
console.log(this.$el.textContent) // 原始的值
this.$nextTick(function () {console.log(this.$el.textContent) // 修改后的值
})
$nextTick() 会返回一个 Promise 对象可以是用async/await完成相同作用的事情
this.message 修改后的值
console.log(this.$el.textContent) // 原始的值
await this.$nextTick()
console.log(this.$el.textContent) // 修改后的值
三、实现原理
源码位置/src/core/util/next-tick.js
callbacks也就是异步操作队列
callbacks新增回调函数后又执行了timerFunc函数pending是用来标识同一个时间只能执行一次
export function nextTick(cb?: Function, ctx?: Object) {let _resolve;// cb 回调函数会经统一处理压入 callbacks 数组callbacks.push(() {if (cb) {// 给 cb 回调函数执行加上了 try-catch 错误处理try {cb.call(ctx);} catch (e) {handleError(e, ctx, nextTick);}} else if (_resolve) {_resolve(ctx);}});// 执行异步延迟函数 timerFuncif (!pending) {pending true;timerFunc();}// 当 nextTick 没有传入函数参数的时候返回一个 Promise 化的调用if (!cb typeof Promise ! undefined) {return new Promise(resolve {_resolve resolve;});}
}
timerFunc函数定义这里是根据当前环境支持什么方法则确定调用哪个分别有
Promise.then、MutationObserver、setImmediate、setTimeout
通过上面任意一种方法进行降级操作
export let isUsingMicroTask false
if (typeof Promise ! undefined isNative(Promise)) {//判断1是否原生支持Promiseconst p Promise.resolve()timerFunc () {p.then(flushCallbacks)if (isIOS) setTimeout(noop)}isUsingMicroTask true
} else if (!isIE typeof MutationObserver ! undefined (isNative(MutationObserver) ||MutationObserver.toString() [object MutationObserverConstructor]
)) {//判断2是否原生支持MutationObserverlet counter 1const observer new MutationObserver(flushCallbacks)const textNode document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})timerFunc () {counter (counter 1) % 2textNode.data String(counter)}isUsingMicroTask true
} else if (typeof setImmediate ! undefined isNative(setImmediate)) {//判断3是否原生支持setImmediatetimerFunc () {setImmediate(flushCallbacks)}
} else {//判断4上面都不行直接用setTimeouttimerFunc () {setTimeout(flushCallbacks, 0)}
}
无论是微任务还是宏任务都会放到flushCallbacks使用
这里将callbacks里面的函数复制一份同时callbacks置空
依次执行callbacks里面的函数
function flushCallbacks () {pending falseconst copies callbacks.slice(0)callbacks.length 0for (let i 0; i copies.length; i) {copies[i]()}
}
小结
把回调函数放入callbacks等待执行将执行函数放到微任务或者宏任务中事件循环到了微任务或者宏任务执行函数依次执行callbacks中的回调
⭐ 写在最后 请大家不吝赐教,在下方评论或者私信我,十分感谢. ✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式 ✅ 认为我部分代码过于老旧,可以提供新的API或最新语法 ✅ 对于文章中部分内容不理解 ✅ 解答我文章中一些疑问 ✅ 认为某些交互,功能需要优化,发现BUG ✅ 想要添加新功能,对于整体的设计,外观有更好的建议 最后感谢各位的耐心观看既然都到这了点个 赞再走吧