Vue2.6中的nextTick方法分析

本篇文章给大家带来的内容是关于vue2.6中的nexttick方法分析),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

浅析 Vue 2.6 中的 nextTick 方法。

事件循环

JS 的 事件循环任务队列 其实是理解 nextTick 概念的关键。
这个网上其实有很多优质的文章做了详细介绍,我就简单过过了。

以下内容适用于浏览器端 JS,NodeJS 的事件循环机制并不相同。

规范中规定 task 分为两大类: task(macrotask) 和 microtask。

立即学习“前端免费学习笔记(深入)”;

通常认为是 task 的任务源:

setTimeout / setIntervalsetImmediateMessageChannelI/OUI rendering

登录后复制

通常认为是 microtask 的任务源:

Promiseprocess.nextTickMutationObserverObject.observe(已废弃)

登录后复制

简单概况:(这里是官方规范)

首先开始执行 script 脚本,直到执行上下文栈为空时,开始清空 microtask 队列里的任务,队列嘛,先入先出,出一个执行一个,清空完毕,走事件循环。

事件循环:不断地去取 task 队列的中的一个任务推入栈中执行,并在当次循环里依次清空 microtask 队列里的任务,清空之后,可能会触发页面更新渲染(由浏览器决定)。

之后重复 事件循环 步骤。

nextTick

Vue 中数据的变化到 DOM 的更新渲染是一个异步过程。
此方法便用于在 DOM 更新循环结束之后执行延迟回调。
使用方法很简单:

// 修改数据vm.msg = 'Hello';// DOM 还没有更新Vue.nextTick(function() {  // DOM 更新了});// 作为一个 Promise 使用Vue.nextTick().then(function() {  // DOM 更新了});

登录后复制

源码 去除注释,其实也只有不到一百来行,整体还是很容易理解的。

这里划成 3 个部分介绍。

模块变量

介绍 引入的模块 和 定义的变量。

// noop 空函数,可用作函数占位符import { noop } from 'shared/util';// Vue 内部的错误处理函数import { handleError } from './error';// 判断是IE/IOS/内置函数import { isIE, isIOS, isNative } from './env';// 使用 MicroTask 的标识符export let isUsingMicroTask = false;// 以数组形式存储执行的函数const callbacks = [];// nextTick 执行状态let pending = false;// 遍历函数数组执行每一项函数function flushCallbacks() {  pending = false;  const copies = callbacks.slice(0);  callbacks.length = 0;  for (let i = 0; i < copies.length; i++) {    copies[i]();  }}

登录后复制

异步延迟函数

接下来是核心的 异步延迟函数。这里不同的 Vue 版本采用的策略其实并不相同。

2.6 版本优先使用 microtask 作为异步延迟包装器。

2.5 版本则是 macrotask 结合 microtask。然而,在重绘之前状态改变时会有小问题(如 #6813)。此外,在事件处理程序中使用 macrotask 会导致一些无法规避的奇怪行为(如#7109,#7153,#7546,#7834,#8109)。

所以 2.6 版本现在又改用 microtask 了,为什么是又呢。。因为 2.4 版本及之前也是用的 microtask。。。

microtask 在某些情况下也是会有问题的,因为 microtask 优先级比较高,事件会在顺序事件(如#4521,#6690 有变通方法)之间甚至在同一事件的冒泡过程中触发(#6566)。

// 核心的异步延迟函数,用于异步延迟调用 flushCallbacks 函数let timerFunc;// timerFunc 优先使用原生 Promise// 原本 MutationObserver 支持更广,但在 iOS >= 9.3.3 的 UIWebView 中,触摸事件处理程序中触发会产生严重错误if (typeof Promise !== 'undefined' && isNative(Promise)) {  const p = Promise.resolve();  timerFunc = () => {    p.then(flushCallbacks);    // IOS 的 UIWebView,Promise.then 回调被推入 microtask 队列但是队列可能不会如期执行。    // 因此,添加一个空计时器“强制”执行 microtask 队列。    if (isIOS) setTimeout(noop);  };  isUsingMicroTask = true;  // 当原生 Promise 不可用时,timerFunc 使用原生 MutationObserver  // 如 PhantomJS,iOS7,Android 4.4  // issue #6466 MutationObserver 在 IE11 并不可靠,所以这里排除了 IE} else if (  !isIE &&  typeof MutationObserver !== 'undefined' &&  (isNative(MutationObserver) ||    // PhantomJS 和 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;  // 如果原生 setImmediate 可用,timerFunc 使用原生 setImmediate} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {  timerFunc = () => {    setImmediate(flushCallbacks);  };} else {  // 最后的倔强,timerFunc 使用 setTimeout  timerFunc = () => {    setTimeout(flushCallbacks, 0);  };}

登录后复制

一句话总结优先级:microtask 优先
Promise > MutationObserver > setImmediate > setTimeout

nextTick 函数

nextTick 函数。接受两个参数:

cb 回调函数:是要延迟执行的函数;

ctx:指定 cb 回调函数 的 this 指向

Vue 实例方法 $nextTick 做了进一步封装,把 ctx 设置为当前 Vue 实例

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);    }  });  // 执行异步延迟函数 timerFunc  if (!pending) {    pending = true;    timerFunc();  }  // 当 nextTick 没有传入函数参数的时候,返回一个 Promise 化的调用  if (!cb && typeof Promise !== 'undefined') {    return new Promise(resolve => {      _resolve = resolve;    });  }}

登录后复制

小结

整体看过来,感觉还是比较好理解的吧~ 2.6 版本相比之前简化了一点。

小结一下,每次调用 Vue.nextTick(cb) 会做些什么:
cb 函数经处理压入 callbacks 数组,执行 timerFunc 函数,延迟调用 flushCallbacks 函数,遍历执行 callbacks 数组中的所有函数。

延迟调用优先级如下:
Promise > MutationObserver > setImmediate > setTimeout

版本差异

其实 Vue 2.4、2.5、2.6 版本的 nextTick 策略都略不一样。

整体 2.62.4 的比较相似。(仔细瞅了瞅,基本就是一样的,2.6 timerFunc 多了个 setImmediate 判断)

2.5 版本其实也差不多。。。源码写法有些不一样,整体优先级是:Promise > setImmediate > MessageChannel > setTimeout,如果更新是在 v-on 事件处理程序中触发的,nextTick 会优先使用 macrotask。

以上就是Vue2.6中的nextTick方法分析的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2732835.html

(0)
上一篇 2025年3月8日 00:49:20
下一篇 2025年3月8日 00:49:26

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • JavaScript基础数据的梳理

    本篇文章给大家带来的内容是关于javascript基础数据的梳理,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 看了一些资料,结合ES6、高程和MDN,对JS核心知识点进行了梳理。由于篇幅有限,这里只对我认为重要的知识做了…

    编程技术 2025年3月8日
    200
  • JavaScript中作用域链与执行环境的介绍(图文)

    本篇文章给大家带来的内容是关于JavaScript中作用域链与执行环境的介绍(图文),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 每一个函数存在一个[[Scope]]内部属性,包含了一个函数被创建得作用域中对象得集合,这…

    2025年3月8日
    200
  • nodejs实现webservice的问题分析

    本篇文章给大家带来的内容是关于nodejs实现webservice的问题分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 库,工具 node-soapsoapui 创建 注意args里参数顺序 const soap = …

    2025年3月8日 编程技术
    200
  • react路由的简单用法(代码示例)

    本篇文章给大家带来的内容是关于react路由的简单用法(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 我要的是简单粗暴的路由 习惯了 vue-router 路由的用法,再用react-router总感觉挺麻烦的…

    2025年3月8日 编程技术
    200
  • Vue CLI3.0中使用jQuery和Bootstrap的教程(详细步骤)

    本篇文章给大家带来的内容是关于vue cli3.0中使用jquery和bootstrap的教程(详细步骤),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 Vue 中使用 jQuery 和 Bootstrap 不是特别符合 …

    2025年3月8日
    200
  • JavaScript中的this的详细分析

    本篇文章给大家带来的内容是关于JavaScript中的this的详细分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 只需要记住几个口诀就能正确找到this的指向: 1.不管函数或者方法是如何声明的,要看这个函数或者方法…

    2025年3月8日 编程技术
    200
  • JavaScript运行机制的详细介绍(代码示例)

    本篇文章给大家带来的内容是关于JavaScript运行机制的详细介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 一、引子 本文介绍javascript运行机制,这一部分比较抽象,我们先从一道面试题入手: c…

    2025年3月8日 编程技术
    200
  • Javascript闭包的代码示例

    本篇文章给大家带来的内容是关于Javascript闭包的代码示例,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 闭包 当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露 //内部的函数被返回…

    编程技术 2025年3月8日
    200
  • JavaScript闭包的解析(附代码)

    本篇文章给大家带来的内容是关于JavaScript闭包的解析(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。了…

    编程技术 2025年3月8日
    200
  • JavaScript复杂判断逻辑写法技巧

    本篇文章给大家带来的内容是关于JavaScript复杂判断逻辑写法技巧,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 在某些场景中,我们可能会遇到多个判断条件的情况,针对这种情况,我们通常会使使用if/else/switc…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论