外贸站群,护肤品营销策划方案,网站建设的工作计划,朋友圈网站文章怎么做的公众号#xff1a;需要以下pdf#xff0c;关注下方 2023已经过完了#xff0c;让我们来把今年的面试题统计号#xff0c;来备战明年的金三银四#xff01;所以#xff0c;不管你是社招还是校招#xff0c;下面这份前端面试工程师高频面试题#xff0c;请收好。 前言
n…公众号需要以下pdf关注下方 2023已经过完了让我们来把今年的面试题统计号来备战明年的金三银四所以不管你是社招还是校招下面这份前端面试工程师高频面试题请收好。 前言
nextTick 是 Vue 的一个核心实现$nextTick方法将回调延迟到下次DOM更新循环之后执行。Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。
nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列
前置知识 - js事件循环
JS 运行机制
JS 执行是单线程的基于事件循环。事件循环大致分为以下步骤
所有同步任务都在主线程上执行形成一个执行栈。异步任务放进任务队列异步任务分为宏任务和微任务执行栈所有同步任务执行完成就会执行任务队列。对应的异步任务结束等待状态进入执行栈开始执行。主线程不断重复上面的第三步。
主线程的执行过程就是一个 tick而所有的异步结果都是通过 “任务队列” 来调度。 消息队列中存放的是一个个的任务task。 task 分为两大类分别是 macro task 和 micro task并且每个 macro task(宏任务) 结束后都要清空所有的 micro task(微任务)。
如图所示 for (macroTask of macroTaskQueue) {// 执行宏任务handleMacroTask();// 执行所有微任务for (microTask of microTaskQueue) {handleMicroTask(microTask);}
}宏任务 script、setTimeout、setInterval、Node中的setImmediate 等微任务 Promise.then、MutationObserver、Node 中的 Process.nextTick等
nextTick的具体实现原理
上源码
源码分为两部分一是判断当前环境能使用的 API 并保存异步函数二是调用异步函数执行回调队列
timerFunc函数定义根据当前环境支持什么方法则确定调用哪个分别有 Promise.then、MutationObserver、setImmediate、setTimeout通过上面任意一种方法进行降级操作 export let isUsingMicroTask false
const callbacks [] // 回调队列
let pending false// 该方法执行队列中的全部回调
function flushCallbacks () {pending falseconst copies callbacks.slice(0)callbacks.length 0// 执行任务队列for (let i 0; i copies.length; i) {copies[i]()}
}
let timerFunc // 用来保存调用异步任务方法
// 判断1是否原生支持Promise
if (typeof Promise ! undefined isNative(Promise)) {// 保存一个异步任务const p Promise.resolve()timerFunc () {// 执行回调函数p.then(flushCallbacks)if (isIOS) setTimeout(noop)}isUsingMicroTask true
} else if (!isIE typeof MutationObserver ! undefined (isNative(MutationObserver) ||MutationObserver.toString() [object MutationObserverConstructor]
)) {// 判断2是否原生支持MutationObserverlet counter 1const observer new MutationObserver(flushCallbacks)const textNode document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})timerFunc () {counter (counter 1) % 2textNode.data String(counter)}isUsingMicroTask true
} else if (typeof setImmediate ! undefined isNative(setImmediate)) {//判断3是否原生支持setImmediattimerFunc () {setImmediate(flushCallbacks)}
} else {//判断4上面都不行直接用setTimeouttimerFunc () {setTimeout(flushCallbacks, 0)}
} export function nextTick(cb?: Function, ctx?: Object) {let _resolve;
// cb 回调函数会经统一处理压入 callbacks 数组callbacks.push(() {if (cb) {try {cb.call(ctx);} catch (e) {handleError(e, ctx, nextTick);}} else if (_resolve) {_resolve(ctx);}});
// 执行异步延迟函数 timerFuncif (!pending) {pending true;timerFunc();}
// 当 nextTick 没有传入函数参数的时候返回一个 Promise 化的调用if (!cb typeof Promise ! undefined) {return new Promise(resolve {_resolve resolve;});}
}callbacks就是异步操作队列
callbacks新增回调函数后又执行了timerFunc函数pending是用来标识同一个时间只能执行一次 function flushCallbacks () {pending falseconst copies callbacks.slice(0)callbacks.length 0for (let i 0; i copies.length; i) {copies[i]()}
}把回调函数放入callbacks等待执行将执行函数放到微任务或者宏任务中 无论是微任务还是宏任务都会放到flushCallbacks使用这里将callbacks里面的函数复制一份同时callbacks置空
循环遍历执行callbacks里面的函数
总结
Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用nextTick核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现根据当前环境支持什么方法则确定调用哪个 原文链接https://juejin.cn/post/7314493016497684520