从 Event Loop 角度解读 Vue NextTick 源码

本文详细解析了JavaScript中同步与异步任务执行的顺序,重点剖析了nextTick函数的实现原理,以及其在Vue2.x中的应用。同时,提到了前端面试中关于基础知识,尤其是执行上下文、作用域链等内容的重要性。
  1. 先执行同步阻塞任务,同步任务会等待上一个执行完毕以后执行下一个,当同步任务执行完毕,再执行异步任务,遇到异步任务会将异步任务的回调函数注册在异步任务队列里。注意,如果主线程上没有同步任务会直接调用异步任务的微任务。

  2. 执行宏任务,遇到微任务将都添加到微任务队列里。

  3. 开始执行微任务队列,当宏任务执行完后执行微任务队列,直到微任务队列全部执行完,微任务队列为空。

  4. 执行宏任务,如果在执行宏任务期间有微任务,将微任务添加到微任务队列里,执行完宏任务之后执行微任务,直到微任务队列全部执行完。

  5. 继续执行宏任务队列。

重复2, 3, 4,5……直到宏微任务为空。

$nextTick 的实现原理


从字面意思理解,next 下一个,tick 滴答(钟表)来源于定时器的周期性中断(输出脉冲),一次中断表示一个 tick,也被称做一个“时钟滴答”),nextTick 顾名思义就是下一个时钟滴答。看源码,在 Vue 2.x 版本中,nextTick 在 src\core\util 中的一个单独的文件 next-tick.js ,可见 nextTick 的重要性,虽然短短 200 多行,尤大却单独创建一个文件去维护。

接下来我们来看整个文件。

  1. 声明了三个全局变量,callbacks: [] ,pending: Boolean,timerFunc: undefined

  2. 声明了一个函数 flushCallbacks

  3. 一堆 **if,else if **判断。

  4. 抛出了一个函数 nextTick

nextTick 函数

  1. 声明一个局部变量 _resolve 。

  2. 把所有回调函数压进 callbacks 中,以栈的形式的存储所有 callback

  3. 当 pending 为 false 时,执行 timerFunc 函数。

  4. 当没有 callback 的时候,返回一个 Promise 的调用方式,可以用 .then 接收。

timerFunc 函数

我们开始说了,timerFunc 为全局变量,现在调用 timerFunc ,timerFunc 是什么时候被赋值为一个函数,并且函数里执行代码又是什么?

我们看到,这段判断代码总共有四个分支,四个分支里对 timerFunc 有不同的赋值,我们先来看第一个分支。

Promise 分支

if (typeof Promise !== ‘undefined’ && isNative(Promise)) {

const p = Promise.resolve()

timerFunc = () => {

p.then(flushCallbacks)

// In problematic UIWebViews, Promise.then doesn’t completely break, but

// it can get stuck in a weird state where callbacks are pushed into the

// microtask queue but the queue isn’t being flushed, until the browser

// needs to do some other work, e.g. handle a timer. Therefore we can

// “force” the microtask queue to be flushed by adding an empty timer.

if (isIOS) setTimeout(noop)

}

isUsingMicroTask = true

}

复制代码

  1. 判断环境是否支持 Promise 并且 Promise 是否为原生。

  2. 使用 Promise 异步调用 flushCallbacks 函数。

  3. 当执行环境是 iPhone 等,使用 setTimeout 异步调用 noop ,iOS 中在一些异常的webview 中,promise 结束后任务队列并没有刷新所以强制执行 setTimeout 刷新任务队列。

MutationObserver 分支

else if (!isIE && typeof MutationObserver !== ‘undefined’ && (

isNative(MutationObserver) ||

// PhantomJS and iOS 7.x

MutationObserver.toString() === ‘[object MutationObserverConstructor]’

)) {

// Use MutationObserver where native Promise is not available,

// e.g. PhantomJS, iOS7, Android 4.4

// (#6466 MutationObserver is unreliable in IE11)

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

}

复制代码

  1. 对非IE浏览器和是否可以使用 HTML5 新特性 MutationObserver 进行判断。

  2. 实例一个 MutationObserver 对象,这个对象主要是对浏览器 DOM 变化进行监听,当实例化 MutationObserver 对象并且执行对象 observe,设置 DOM 节点发生改变时自动触发回调。

  3. 把 timerFunc 赋值为一个改变 DOM 节点的方法,当 DOM 节点发生改变,触发 flushCallbacks 。(这里其实就是想用利用 MutationObserver 的特性进行异步操作)

setImmediate 分支

else if (typeof setImmediate !== ‘undefined’ && isNative(setImmediate)) {

// Fallback to setImmediate.

// Technically it leverages the (macro) task queue,

// but it is still a better choice than setTimeout.

timerFunc = () => {

setImmediate(flushCallbacks)

}

}

复制代码

  1. 判断 setImmediate 是否存在,setImmediate 是高版本 IE (IE10+) 和 edge 才支持的。

  2. 如果存在,传入 flushCallbacks 执行 setImmediate 。

setTimeout 分支

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

完整版面试题资料免费分享,只需你点赞支持,动动手指点击此处就可领取了

前端实习面试的套路


回顾项目

往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。

面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。

重点在于基础知识

这里指的基础知识包括:前端基础知识和学科基础知识。

前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值