Skip to main content

moregeek program

「Vue系列」之面试官问NextTick是想考察什么?-多极客编程

🌲🌲🌲 前言

    说起来nextTick相信大家也都耳熟能详,虽然在业务开发中用到的次数不是很多,但是在面试题汇总中出现的频率可是不低。那么nextTick到底能考察我们什么知识,我们一块来分析分析。「如果对你有帮助,点赞是对我最大的鼓励哦,如果理解有误的地方,希望大佬指出,不胜感激。❤️」

🌴🌴🌴 铺垫

    在看nextTick之前,我们先铺垫一点相关的前置知识。

🧩🧩🧩 ​异步更新


Vue响应式更新并不是数据变化之后Dom立即发生变化,而是按照一定策略进行更新的


    正是因为Vue是异步更新Dom,所以当我们修改数据之后,Dom节点的内容不会立即修改,我们这样获取Dom节点的新内容的时候,获取的还是旧的内容。

Tipes:为什么Vue要使用异步更新Dom?避免不必要的计算和 DOM 操作,优化性能。

「一定策略:Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。」

const text = ref(null);
let a = ref('0');
const testFun = async () => {
a.value = '111111';
console.log(text.value.innerHTML, 'beforeNextTick');
await nextTick();
console.log(text.value.innerHTML, 'afterNextTick');
};

控制台输出:

「Vue系列」之面试官问NextTick是想考察什么?_回调函数

    那么由此可见,nextTick的回调函数一定是在dom元素更新任务之后立即执行的,那么怎么把他的回调函数放在dom元素更新任务之后呐?这就要说到下一部分:​事件循环「Event Loop」

⚙️⚙️⚙️ ​事件循环

    想要弄明白nextTick的原理,还是需要知道事件循环相关的知识。在这里不细说「毕竟说起来Event Loop就太多了,还涉及到node中事件循环的不同,掘金已经有很多大佬写过,这里就给大家放一张我自己总结的图」

「Vue系列」之面试官问NextTick是想考察什么?_回调函数_02

然后重要说一下在事件循环中各种任务的执行顺序:


  1. 一开始整段脚本作为第一个宏任务执行
  2. 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
  3. 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空
  4. 执行浏览器 UI 线程的渲染工作
  5. 检查是否有Web worker任务,有则执行
  6. 执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

「Vue系列」之面试官问NextTick是想考察什么?_任务队列_03

    根据上面的执行顺序,如果想要nextTick的回调函数一定是在dom元素更新任务之后立即执行的,那么​就需要在更新DOM的那个任务后追加nextTick的回调函数​,下面就从源码的角度去分析一下是怎么实现追加的。

🗂🗂🗂 深入

有了上面的铺垫,我们直接去看源码:

​nextTick​​​ 的源码位于​​src/core/util/next-tick.js​

​nextTick​​源码主要分为两块:


  • 环境兼容
  • 不同方式执行回调队列
    Tipes:在github上看源码的时候将github改为github1s,github秒变vscode,观码体验不要太爽哦
// 环境兼容
// 优先微任务检测
if (typeof Promise !== 'undefined' && isNative(Promise)) {
// 检测浏览器是否原生支持 Promise
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
// 基于typeOf检测一个没有被声明的变量,不会报错
} else if (!isIE && typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) ||
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
// 检测是否支持原生的 MutationObserver
// MutationObserver:是HTML5中的API,是一个用于监视DOM变动
// 它可以监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等
// 回调是放在微任务队列中执行的
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
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
// 检测是否支持原生 setImmediate
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
// 最后使用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}

Tipes:为什么优先使用微任务:按照上面事件循环的执行顺序,执行下一次宏任务之前会执行一次ui渲染,等待时长比微任务要多很多。所以在能使用微任务的时候优先使用微任务,不能使用微任务的时候才使用宏任务,优雅降级。

const callbacks = []
let pending = false
// 遍历执行回调函数
function flushCallbacks () {
pending = false
// 处理nextTick内部嵌套nextTick的操作
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}

...环境兼容...

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)
}
})
// 说明本次循环没有执行timerFunc,遍历执行回调
if (!pending) {
pending = true
// 遍历执行
timerFunc()
}
// 处理不传回调函数的情况
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}

Tipes: nextTick只能获取执行顺序在他前面的dom更改,如果在nextTick后面再次修改,则获取不到。

📖📖📖总结

    从上面涉及到的内容可以总结出,当面试官问道nextTick原理的时候,其实想要考察的有「当然这些都是我瞎猜的哈哈」:

    1.vue的Dom异步更新策略

    2.事件循环相关的知识

    相比于其他Vue的Api来说,nextTick的原理还是比较简单的,而且源码的行数也比较少,所以看看就懂了,哈哈。

「有帮助记得帮我点点赞哦」

最后祝各位大佬学习进步,事业有成!🎆🎆🎆

欢迎关注公众号:廿九前端营地,获取前端资源和我一块学习

Tipes:往期内容

​# 「算法基础」之二叉树的遍历和搜索​

🔗🔗🔗链接

​1.图解Event Loop​

​2.nextTick源码​

©著作权归作者所有:来自51CTO博客作者季夏廿九的原创作品,请联系作者获取转载授权,否则将追究法律责任
「Vue系列」之面试官问NextTick是想考察什么?
https://blog.51cto.com/u_15493764/5056887

Semantic UI 之 下拉菜单 dropdown #yyds干货盘点#-多极客编程

第一步:创建项目 添加JQuery和Semantic UI包、创建dropdown.html页面: 第二步:dropdown.html页面 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>分段</tit

#yyds干货盘点# 前端模块化的全面总结-多极客编程

背景 随着前端功能越来越复杂,前端代码日益膨胀,为了减少维护成本,提高代码的可复用性,前端模块化势在必行。 所有js文件都在一个html中引入,造成以下不良影响: 请求过多。首先我们要依赖多个模块,那样就会发送多个请求,导致请求过多 依赖模糊。我们不知道他们的具体依赖关系是什么,也就是说很容易因为不了解他们之间的依赖关系导致加载先后顺序出错。 难以维护。以上两种原因就导致了很难维护,很可能出现牵

vue3.0的生命周期和父子传值,一学就会#yyds干货盘点#-多极客编程

生命周期 组合式 API 上的生命周期钩子与选项式 API 的名称相同,但前缀为 on:即 mounted 看起来像 onMounted。 setup() {//setup组合式api的入口函数,在beforeCreate之前执行 const count=ref(0) console.log('setup'); onBeforeMount(() => {//组件挂载到

浅谈:为什么vue和react都选择了Hooks?-多极客编程

一、hooks: 什么叫大势所趋?2019年年初,​​react​​ 在 ​​16.8.x​​ 版本正式具备了 ​​hooks​​ 能力。2019年6月,尤雨溪在 vue/github-issues 里提出了关于 ​​vue3 Component API​​ 的提案。(vue hooks的基础)在后续的 ​​react​​ 和 ​​vue3​​ 相关版本中,相关 ​​hooks​​ 能力都开始被更

#yyds干货盘点#弹性布局中让其中一个元素靠右显示-多极客编程

1.效果在弹性布局中如何让最边上的一个往反方向布局2.代码// html<body><div class="container"><div class="item">1</div><div class="item">2</div><div class="item">3</div><div clas

#yyds干货盘点# 系统学习 TypeScript(五)——联合类型-多极客编程

前言 在初步学习了 TypeScript 的变量声明后,对它的静态类型检查功能简直是爱不释手,但同时也发现一个问题:在正常的开发中,一个变量的类型有时可能不仅仅只限于 number 或者 string 中的一种,有可能是两种类型或者更多,比如: // index.js let res; if(userInfo.age && userInfo.age > 12){ r

#yyds干货盘点#CSS实现loading效果效果-多极客编程

1.效果展示2.代码<!DOCTYPE html><html><head><meta charset="UTF-8"><title></title><style type="text/css">*{margin: 0;padding: 0; } .box{width: 100px;height:

#yyds干货盘点# CSS的网页布局总结-多极客编程

一、CSS的网页布局  网页布局结构按照列数可分为单列、两列和三列等几种布局。 1.单列布局 单列布局相对简单,很多复杂布局往往以单列布局为基础。单列布局中的对象位置可固定在左侧、浮在右侧或居中;宽度可用像素值固定、百分比或相对于字号设置。 举个例子 代码 <!DOCTYPE html> <html> <head> <met

# yyds干货盘点 # 基于HTML5打造的一款别踩白板小游戏-多极客编程

背景简介别踩白板这个游戏相信大家都玩过,这个是基于HTML5打造的简单小游戏,在PC端和移动端都能够运行,适应多种平台,今天我们使用原生JS搭配JQuery构建这个小游戏--别踩白板。一、思路分析整体页面是一个大的矩形,长宽比例大概是3:2,然后游戏开始,不断有白板降落,然后一行是4个板,一块黑色板块,其余三块是白色板块,通过板块的点击事件绑定,然后判定是什么颜色,只要是白色的,游戏结束(Game

#yyds干货盘点#弹性布局中让其中一个元素靠右显示-多极客编程

1.效果在弹性布局中如何让最边上的一个往反方向布局2.代码// html<body><div class="container"><div class="item">1</div><div class="item">2</div><div class="item">3</div><div clas

#yyds干货盘点#前端在线预览PDF文件-多极客编程

前言 这里用到了vue-pdf插件,预览PDF相关的操作基本都有实现; 我们需要做的就是各种布局(因为需兼容已有的布局,有的地方可能需要修改),比如翻页按钮,页码展示等等; vue-pdf的GitHub地址:FranckFreiburger/vue-pdf: vue.js pdf viewer (github.com) 目录 入门例子 展示所有页码 翻页操作 封装组件 完整代码 正文 1. 入门例

#yyds干货盘点#前端如何通过antdv组件上传文件-多极客编程

前言 上传文件到云存储一般有两种方式:前端上传和后端上传; 前端上传就是前端自己上传到OSS云存储,然后将远程链接传给后端; 后端上传就是前端只负责上传本地文件,然后后端酌情处理,可以上传到云存储,也可以本地存储; 因为andtv官方的例子就是介绍的第二种,所以本篇我们来介绍第一种方式,前端自己上传到云存储; 这里用的是Ant Design Vue的 Upload组件; 目录 组件介绍 上传例