Vue2和Vue3的nextTick怎么实现 您所在的位置:网站首页 循环队列模板怎么设置 Vue2和Vue3的nextTick怎么实现

Vue2和Vue3的nextTick怎么实现

2023-05-06 09:22| 来源: 网络整理| 查看: 265

Vue2和Vue3的nextTick怎么实现 发布时间:2023-04-27 11:51:23 来源:亿速云 阅读:58 作者:iii 栏目:开发技术

这篇“Vue2和Vue3的nextTick怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Vue2和Vue3的nextTick怎么实现”文章吧。

一次弄懂 Vue2 和 Vue3 的 nextTick 实现原理Vue2 中的 nextTick

在 Vue2 中,nextTick 的实现基于浏览器的异步任务队列和微任务队列。

异步任务队列

在浏览器中,每个宏任务结束后会检查微任务队列,如果有任务则依次执行。当所有微任务执行完成后,才会执行下一个宏任务。因此可以通过将任务作为微任务添加到微任务队列中,来确保任务在所有宏任务执行完毕后立即执行。

而使用 setTimeout 可以将任务添加到异步任务队列中,在下一轮事件循环中执行。

在 Vue2 中,如果没有指定执行环境,则会优先使用 Promise.then / MutationObserver,否则使用 setTimeout。

javascript // src/core/util/next-tick.js /* istanbul ignore next */ const callbacks = [] let pending = false function flushCallbacks() {   pending = false   const copies = callbacks.slice(0)   callbacks.length = 0   for (let i = 0; i  {     setImmediate(flushCallbacks)   } } else if (   typeof MessageChannel !== 'undefined' &&   (isNative(MessageChannel) ||     // PhantomJS     MessageChannel.toString() === '[object MessageChannelConstructor]') ) {   const channel = new MessageChannel()   const port = channel.port2   channel.port1.onmessage = flushCallbacks   macroTimerFunc = () => {     port.postMessage(1)   } } else {   // 使用 setTimeout   macroTimerFunc = () => {     setTimeout(flushCallbacks, 0)   } } if (typeof Promise !== 'undefined' && isNative(Promise)) {   // 使用 Promise.then   const p = Promise.resolve()   microTimerFunc = () => {     p.then(flushCallbacks)   } } else {   // 使用 MutationObserver   const observer = new MutationObserver(flushCallbacks)   const textNode = document.createTextNode(String(1))   observer.observe(textNode, {     characterData: true   })   microTimerFunc = () => {     textNode.data = String(1)   } } 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     if (useMacroTask) {       macroTimerFunc()     } else {       microTimerFunc()     }   }   if (!cb && typeof Promise !== 'undefined') {     return new Promise(resolve => {       _resolve = resolve     })   } }宏任务和微任务

在 Vue2 中,可以通过设置 useMacroTask 来使 nextTick 方法使用宏任务或者微任务。

Vue2 中默认使用微任务,在没有原生 Promise 和 MutationObserver 的情况下,才会改用 setTimeout。

javascript let microTimerFunc let macroTimerFunc let useMacroTask = false // 默认使用微任务 if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {   // 使用 setImmediate   macroTimerFunc = () => {     setImmediate(flushCallbacks)   } } else if (   typeof MessageChannel !== 'undefined' &&   (isNative(MessageChannel) ||     // PhantomJS     MessageChannel.toString() === '[object MessageChannelConstructor]') ) {   const channel = new MessageChannel()   const port = channel.port2   channel.port1.onmessage = flushCallbacks   macroTimerFunc = () => {     port.postMessage(1)   } } else {   // 使用 setTimeout   macroTimerFunc = () => {     setTimeout(flushCallbacks, 0)   } } if (typeof Promise !== 'undefined' && isNative(Promise)) {   // 使用 Promise.then   const p = Promise.resolve()   microTimerFunc = () => {     p.then(flushCallbacks)   } } else {   // 使用 MutationObserver   const observer = new MutationObserver(flushCallbacks)   const textNode = document.createTextNode(String(1))   observer.observe(textNode, {     characterData: true   })   microTimerFunc = () => {     textNode.data = String(1)   } } 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     if (useMacroTask) {       macroTimerFunc()     } else {       microTimerFunc()     }   }   if (!cb && typeof Promise !== 'undefined') {     return new Promise(resolve => {       _resolve = resolve     })   } }总结

在 Vue2 中,nextTick 的实现原理基于浏览器的异步任务队列和微任务队列。Vue2 默认使用微任务,在没有原生 Promise 和 MutationObserver 的情况下才会改用 setTimeout。

Vue3 中的 nextTick

在 Vue3 中,nextTick 的实现有了较大变化,主要是为了解决浏览器对 Promise 的缺陷和问题。

Promise 在浏览器中的问题

在浏览器中,Promise 有一个缺陷:如果 Promise 在当前事件循环中被解决,那么在 then 回调函数之前添加的任务将不能在同一个任务中执行。

例如:

javascript Promise.resolve().then(() => {   console.log('Promise 1') }).then(() => {   console.log('Promise 2') }) console.log('Hello')

输出结果为:

Hello Promise 1 Promise 2

这是因为 Promise 虽然是微任务,但是需要等到当前宏任务结束才能执行。

Vue3 中解决 Promise 缺陷的方法

在 Vue3 中,通过使用 MutationObserver 和 Promise.resolve().then() 来解决 Promise 在浏览器中的缺陷。具体实现如下:

javascript const queue: Array = [] let has: { [key: number]: boolean } = {} let flushing = false let index = 0 function resetSchedulerState() {   queue.length = 0   has = {}   flushing = false } function flushSchedulerQueue() {   flushing = true   let job   while ((job = queue.shift())) {     if (!has[job.id]) {       has[job.id] = true       job()     }   }   resetSchedulerState() } let macroTimerFunc let microTimerFunc if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {   macroTimerFunc = () => {     setImmediate(flushSchedulerQueue)   } } else {   macroTimerFunc = () => {     setTimeout(flushSchedulerQueue, 0)   } } if (typeof Promise !== 'undefined' && isNative(Promise)) {   const p = Promise.resolve()   microTimerFunc = () => {     p.then(flushSchedulerQueue)     if (isIOS) setTimeout(noop)   } } else {   microTimerFunc = macroTimerFunc } export function nextTick(fn?: Function): Promise {   const id = index++   const job = fn.bind(null)   queue.push(job)   if (!flushing) {     if (useMacroTask) {       macroTimerFunc()     } else {       microTimerFunc()     }   }   if (!fn && typeof Promise !== 'undefined') {     return new Promise(resolve => {       resolvedPromise.then(() => {         if (has[id] || !queue.includes(job)) {           return         }         queue.splice(queue.indexOf(job), 1)         resolve()       })     })   } }

在 Vue3 中,nextTick 的实现原理基于MutationObserver 和 Promise.resolve().then(),通过 MutationObserver 监测 DOM 变化,在下一个微任务中执行回调函数。

而如果当前浏览器不支持原生 Promise,则使用 setTimeout 来模拟 Promise 的行为,并在回调函数执行前添加一个空的定时器来强制推迟执行(解决 iOS 中 setTimeout 在非激活标签页中的问题)。

如果需要等待所有回调函数执行完成,则可以通过返回一个 Promise 对象来实现。

javascript export function nextTick(fn?: Function): Promise {   const id = index++   const job = fn.bind(null)   queue.push(job)   if (!flushing) {     if (useMacroTask) {       macroTimerFunc()     } else {       microTimerFunc()     }   }   if (!fn && typeof Promise !== 'undefined') {     return new Promise(resolve => {       resolvedPromise.then(() => {         if (has[id] || !queue.includes(job)) {           return         }         queue.splice(queue.indexOf(job), 1)         resolve()       })     })   } }

以上就是关于“Vue2和Vue3的nextTick怎么实现”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

推荐阅读: vue分页效果 基于vue和springmvc前后端分离,json类接口调用介绍

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:[email protected]进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue nexttick 上一篇新闻:idea运行main方法或Test避免编译整个应用怎么实现 下一篇新闻:C++怎么用代理模式实现远程代理,虚拟代理和保护代理 猜你喜欢 使用Python怎么生成一个rsa密钥对 如何在python中利用Opencv实现一个人脸识别功能 Python OpenCV利用笔记本摄像头实现人脸检测 python使用KNN算法识别手写数字 Python3.5运算符操作的示例分析 如何在Python项目中将对象转换为json 怎么在Python中使用PyQt5实现可视化爬虫工具 详解用python实现基本的学生管理系统(文件存储版)(python3) Python基础教程之if判断,while循环,循环嵌套 python3通过selenium爬虫如何获取到dj商品


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有