热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Vue2.6中的nextTick方法分析

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

浅析 Vue 2.6 中的 nextTick 方法。

事件循环

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

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

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

通常认为是 task 的任务源:

setTimeout / setInterval
setImmediate
MessageChannel
I/O
UI rendering

通常认为是 microtask 的任务源:

Promise
process.nextTick
MutationObserver
Object.observe(已废弃)

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

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

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

  3. 之后重复 事件循环 步骤。

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 

异步延迟函数

接下来是核心的 异步延迟函数。这里不同的 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 函数。接受两个参数:

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

  2. 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方法分析的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
author-avatar
mobiledu2502929447
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有