0

0

Vue2.6中的nextTick方法分析

不言

不言

发布时间:2019-02-28 11:58:15

|

2592人浏览过

|

来源于segmentfault

转载

本篇文章给大家带来的内容是关于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 < copies.length; i++) {
    copies[i]();
  }
}

异步延迟函数

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

ShoopD 网上商店系统
ShoopD 网上商店系统

用 php + mysql 驱动的在线商城系统,我们的目标为中国的中小企业及个人提供最简洁,最安全,最高效的在线商城解决方案,使用了自建的会员积分折扣功能,不同的会员组有不同的折扣,让您的商店吸引更多的后续客户。 系统自动加分处理功能,自动处理会员等级,免去人工处理的工作量,让您的商店运作起来更方便省事 采用了自建的直接模板技术,免去了模板解析时间,提高了代码利用效率 独立开发的购物车系统,使用最

下载

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。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

363

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

558

2023.08.10

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

505

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

240

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

246

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5209

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

470

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

204

2023.09.04

ip地址修改教程大全
ip地址修改教程大全

本专题整合了ip地址修改教程大全,阅读下面的文章自行寻找合适的解决教程。

27

2025.12.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue 教程
Vue 教程

共42课时 | 5.6万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 0.9万人学习

Vue.js 微实战--十天技能课堂
Vue.js 微实战--十天技能课堂

共18课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号