You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
// 修改数据vm.msg='Hello'// DOM 还没有更新Vue.nextTick(function(){// DOM 更新了})// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)Vue.nextTick().then(function(){// DOM 更新了})
/* @flow *//* globals MutationObserver */// 空函数import{noop}from'shared/util'// 处理错误的函数import{handleError}from'./error'// 判断运行环境import{isIE,isIOS,isNative}from'./env'// 是否使用微任务的标识符exportletisUsingMicroTask=false// 存放回调函数的数组constcallbacks=[]// nexttick 执行状态letpending=false// 遍历回调函数functionflushCallbacks(){pending=false// 浅拷贝存放回调函数的数组constcopies=callbacks.slice(0)callbacks.length=0for(leti=0;i<copies.length;i++){copies[i]()}}// Here we have async deferring wrappers using microtasks.// In 2.5 we used (macro) tasks (in combination with microtasks).// However, it has subtle problems when state is changed right before repaint// (e.g. #6813, out-in transitions).// Also, using (macro) tasks in event handler would cause some weird behaviors// that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109).// So we now use microtasks everywhere, again.// A major drawback of this tradeoff is that there are some scenarios// where microtasks have too high a priority and fire in between supposedly// sequential events (e.g. #4521, #6690, which have workarounds)// or even between bubbling of the same event (#6566).lettimerFunc// The nextTick behavior leverages the microtask queue, which can be accessed// via either native Promise.then or MutationObserver.// MutationObserver has wider support, however it is seriously bugged in// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It// completely stops working after triggering a few times... so, if native// Promise is available, we will use it:/* istanbul ignore next, $flow-disable-line */if(typeofPromise!=='undefined'&&isNative(Promise)){// 如果浏览器支持原生 promise, 则直接使用 promiseconstp=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)}// 将是否使用微任务改为 trueisUsingMicroTask=true}elseif(!isIE&&typeofMutationObserver!=='undefined'&&(isNative(MutationObserver)||// PhantomJS and iOS 7.xMutationObserver.toString()==='[object MutationObserverConstructor]')){// Use MutationObserver where native Promise is not available,// e.g. PhantomJS, iOS7, Android 4.4// (#6466 MutationObserver is unreliable in IE11)// MutationObserver:如果浏览器支持 MutationObserver,则使用 MutationObserver//(该 API 是个微任务,可以监听 DOM 元素是否变动,当所有 DOM 操作完成后,会触发相应的事件)// 当 不支持 promise 时,优先使用该 APIletcounter=1constobserver=newMutationObserver(flushCallbacks)consttextNode=document.createTextNode(String(counter))observer.observe(textNode,{characterData: true})timerFunc=()=>{counter=(counter+1)%2textNode.data=String(counter)}isUsingMicroTask=true}elseif(typeofsetImmediate!=='undefined'&&isNative(setImmediate)){// Fallback to setImmediate.// Techinically it leverages the (macro) task queue,// but it is still a better choice than setTimeout.// setImmediate:宏任务,只支持 IE、edge 浏览器。// 与 setTimeout 相比,优势在于它是立即执行,而 setTimeout 最小间隔是 4mstimerFunc=()=>{setImmediate(flushCallbacks)}}else{// Fallback to setTimeout.timerFunc=()=>{setTimeout(flushCallbacks,0)}}// 封装的nextTick函数,cb:回调函数,ctx:this 指向exportfunctionnextTick(cb?: Function,ctx?: Object){let_resolve// 回调函数统一进入 callbacks 中进行处理callbacks.push(()=>{if(cb){try{cb.call(ctx)}catch(e){handleError(e,ctx,'nextTick')}}elseif(_resolve){_resolve(ctx)}})if(!pending){pending=truetimerFunc()}// 如果没有传入回调函数,且当前环境支持 promise ,则返回一个 promise 对象// $flow-disable-lineif(!cb&&typeofPromise!=='undefined'){returnnewPromise(resolve=>{_resolve=resolve})}}
The text was updated successfully, but these errors were encountered:
用法
nextTick 是 vue 中的一个重要的API,先看下官方文档的介绍。
vue.nextTick( [callback, context] )
参数:
用法:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。可以看出,nextTick 实际上就是 DOM 更新后的一个回调。那DOM更新的时机是什么时候呢?
DOM 的更新时机
这要从 js 的运行机制说起。(硬广:js 的运行机制)。简单点说就是,js 代码的执行顺序是基于事件循环的,大致分为几个步骤:
当然异步任务分为宏任务和微任务。具体就不说了,可以看下硬广。主线程在同步任务执行完后,会首先从任务队列中查找并执行微任务,直到最后一个微任务执行完,第一次事件循环结束。
开始第二次事件循环,任务队列中第一个宏任务变成同步任务,被首先执行,然后执行微任务,不断这样循环执行,直到所有任务执行完毕。
而 DOM 的更新时机则是在微任务执行结束后。我们看个栗子:
我们可以看到,DOM 的渲染是在微任务之后的,而且在下一次事件循环之前。
nextTick 源码解析
The text was updated successfully, but these errors were encountered: