当前位置: 首页 > Web前端 > vue.js

Vue的nextTick原理

时间:2023-03-31 22:22:44 vue.js

鑳屾櫙鐭ュ叾鐒剁煡鍏舵墍浠ワ紝Vue浣滀负鐩墠鏈€涓绘祦鐨勫墠绔疢VVM妗嗘灦涔嬩竴锛屽湪鐔熺粌浣跨敤鐨勫熀纭€涓婁簡瑙e叾瀹炵幇鍘熺悊鏄潪甯告湁鎰忎箟鐨勩€傞槄璇籚ue婧愮爜鏄竴涓緢濂界殑瀛︿範鏂瑰紡銆傚畠涓嶄粎鍙互甯姪鎴戜滑鏇村揩鍦拌В鍐冲伐浣滀腑閬囧埌鐨勯棶棰橈紝杩樺彲浠ュ€熼壌浼樼婧愮爜鐨勭粡楠岋紝瀛︿範涓撳濡備綍鍙戠幇闂銆佹€濊€冮棶棰樸€佽В鍐抽棶棰樸€傜紪鍐欐爣鍑嗗寲涓旀槗浜庣淮鎶ょ殑楂樿川閲忎唬鐮併€傛湰鏂囬儴鍒嗘枃瀛楀拰浠g爜鐗囨涓昏鏉ヨ嚜Vue瀹樻柟鏂囨。鍜岀█鍦熸帢閲戠ぞ鍖猴紝鏂囩珷鏈熬鏄庣‘鏍囨敞浜嗗紩鐢ㄦ潵婧愩€傚鏈変镜鏉冿紝璇疯仈绯诲垹闄ゃ€傪煉℃俯棣ㄦ彁绀猴細鏈枃鍏ㄦ枃3277瀛楋紝鎺ㄨ崘闃呰鏃堕棿15鍒嗛挓锛屽共鏉紒1.寮傛鏇存柊闃熷垪浣犲彲鑳芥病鏈夋敞鎰忓埌锛孷ue鍦ㄦ洿鏂癉OM鏃舵槸寮傛鎵ц鐨勩€傚彧瑕佹娴嬪埌鏁版嵁鍙樺寲锛孷ue灏变細鎵撳紑涓€涓槦鍒楋紝缂撳啿鎵€鏈夊彂鐢熷湪鍚屼竴涓簨浠跺惊鐜腑鐨勬暟鎹彉鍖栥€傚鏋滃悓涓€涓猈atcher琚娆¤Е鍙戯紝瀹冨彧浼氳鎺ㄥ叆闃熷垪涓€娆°€傝繖绉嶇紦鍐叉椂鐨勯噸澶嶆暟鎹垹闄ゅ浜庨伩鍏嶄笉蹇呰鐨勮绠楀拰DOM鎿嶄綔闈炲父閲嶈銆傜劧鍚庯紝鍦ㄤ笅涓€涓簨浠跺惊鐜€渢ick鈥濅腑锛孷ue鍒锋柊闃熷垪骞舵墽琛屽疄闄咃紙鍘婚噸锛夊伐浣溿€俈ue鍐呴儴灏濊瘯浣跨敤鍘熺敓鐨凱romise.then銆丮utationObserver鍜宻etImmediate鏉ュ疄鐜板紓姝ラ槦鍒椼€傚鏋滄墽琛岀幆澧冧笉鏀寔锛屽畠灏嗕娇鐢╯etTimeout(fn,0)浠f浛銆備緥濡傦紝褰撴偍璁剧疆vm.someData='newvalue'鏃讹紝缁勪欢涓嶄細绔嬪嵆閲嶆柊娓叉煋銆傚埛鏂伴槦鍒楁椂锛岀粍浠朵細鍦ㄤ笅涓€涓簨浠跺惊鐜€渢ick鈥濇椂鏇存柊銆傚ぇ澶氭暟鏃跺€欐垜浠笉闇€瑕佸叧蹇冭繖涓繃绋嬶紝浣嗘槸濡傛灉浣犳兂鏍规嵁鏇存柊鐨凞OM鐘舵€佸仛涓€浜涗簨鎯咃紝瀹冨彲鑳戒細寰堟鎵嬨€傝櫧鐒禫ue.js閫氬父榧撳姳寮€鍙戜汉鍛樹娇鐢ㄢ€滄暟鎹┍鍔ㄢ€濈殑鎬濈淮鏂瑰紡骞堕伩鍏嶇洿鎺ユ帴瑙OM锛屼絾鏈夋椂鎴戜滑涓嶅緱涓嶈繖鏍峰仛銆傝绛夊緟Vue鍦ㄦ暟鎹洿鏀瑰悗瀹屾垚鏇存柊DOM锛岃鍦ㄦ暟鎹洿鏀瑰悗绔嬪嵆浣跨敤Vue.nextTick(callback)銆傝繖鏍峰洖璋冨嚱鏁板氨浼氬湪DOM鏇存柊瀹屾垚鍚庤璋冪敤銆備緥濡傦細{{message}}

varvm=newVue({el:'#example',data:{message:'123'}});vm.message='鏂版秷鎭?;//鏀瑰彉鏁版嵁vm.$el.textContent==='newmessage';//falseVue.nextTick(function(){vm.$el.textContent==='鏂版秷鎭?;//true});鍦ㄧ粍浠朵腑浣跨敤vm.$nextTick()瀹炰緥鏂规硶闈炲父鏂逛究锛屽洜涓哄畠涓嶉渶瑕佸叏灞€鐨刅ue锛屽洖璋冨嚱鏁颁腑鐨則his浼氳嚜鍔ㄧ粦瀹氬埌褰撳墠Vue瀹炰緥锛歏ue.component('example',{template:'{{message}}',data:function(){return{message:'notupdated'};},methods:{updateMessage:function(){this.message='宸茬粡鏇存柊';console.log(this.$el.textContent);//=>'鏈洿鏂?this.$nextTick(function(){console.log(this.$el.textContent);//=>'鏈夋洿鏂?});}}});鍥犱负$nextTick()杩斿洖涓€涓狿romise瀵硅薄锛屼綘鍙互浣跨敤鏂扮殑ES2017async/await璇硶鏉ュ畬鎴愬悓鏍风殑浜嬫儏锛歮ethods:{updateMessage:asyncfunction(){this.mes榧犲熬鑽?'鏇存柊';console.log(this.$el.textContent);//=>'鏈洿鏂?awaitthis.$nextTick();console.log(this.$el.textContent);//=>'Updated'}}nextTick鎺ユ敹涓€涓洖璋冨嚱鏁颁綔涓哄弬鏁帮紝寤惰繜鍥炶皟鍑芥暟鐨勬墽琛岋紝鐩村埌DOM琚洿鏂帮紱nextTick鍦ㄤ笅涓€涓狣OM鏇存柊鍛ㄦ湡缁撴潫鍚庢墽琛屽欢杩熷洖璋冿紝鍦ㄤ慨鏀规暟鎹悗浣跨敤nextTick锛岄偅涔堜綘鍙互鍦ㄥ洖璋冧腑鑾峰彇鏇存柊鍚庣殑DOM浣跨敤鍦烘櫙锛氬綋浣犳兂鏍规嵁鏈€鏂扮殑鏁版嵁鎿嶄綔鐢熸垚鐨凞OM鏃讹紝鎶婅繖涓猲extTick鍥炶皟涓殑鎿嶄綔锛?.鍓嶇疆鐭ヨ瘑nextTick鍑芥暟鐨勪綔鐢ㄥ彲浠ョ悊瑙d负寮傛鎵ц浼犲叆鐨勫嚱鏁帮紝杩欓噷绠€鍗曚粙缁嶄竴涓嬩粈涔堟槸寮傛鎵ц锛屼粠JS杩愯鏈哄埗璇磋捣2.1JS杩愯鏈哄埗JS鎵ц鏄崟绾跨▼鐨勶紝鎵€璋撳崟绾跨▼浜嬩欢浠诲姟灏辨槸鍦ㄤ竴涓槦鍒椾腑鎵ц锛屼笂涓€涓换鍔″畬鎴愶紝涓嬩竴涓换鍔′細鎵ц锛岃繖涓槸鍚屾浠诲姟銆備负浜嗛伩鍏嶄笂涓€涓换鍔℃墽琛屼簡寰堜箙锛屼笅涓€涓换鍔℃棤娉曟墽琛岀殑鎯呭喌锛屽紩鍏ヤ簡寮傛浠诲姟鐨勬蹇点€侸S杩愯鏈哄埗鍙互绠€鍗曠殑鎸夌収浠ヤ笅姝ラ杩涜銆傛墍鏈夌殑鍚屾浠诲姟閮藉湪涓荤嚎绋嬩笂鎵ц锛屽舰鎴愪竴涓墽琛屼笂涓嬫枃鏍堛€傞櫎浜嗕富绾跨▼涔嬪锛岃繕鏈変竴涓换鍔¢槦鍒楋紙taskqueue锛夈€傚彧瑕佸紓姝ヤ换鍔℃湁杩愯缁撴灉锛屽畠鐨勫洖璋冨嚱鏁板氨浼氫綔涓轰换鍔″姞鍏ュ埌浠诲姟闃熷垪涓€備竴鏃︽墽琛屾爤涓殑鎵€鏈夊悓姝ヤ换鍔¢兘鎵ц瀹屾瘯锛屽氨浼氳鍙栦换鍔¢槦鍒楋紝鏌ョ湅鍏朵腑鏈夊摢浜涗换鍔★紝娣诲姞鍒版墽琛屾爤涓紝骞舵墽琛屻€備富绾跨▼涓嶆柇閲嶅涓婇潰鐨勭涓夋銆傚畠閫氬父琚О涓轰簨浠跺惊鐜紙EventLoop锛夈€?.2寮傛浠诲姟鐨勭绫籲extTick鍑芥暟寮傛鎵ц浼犲叆鍑芥暟锛屽睘浜庡紓姝ヤ换鍔°€傛湁涓ょ绫诲瀷鐨勫紓姝ヤ换鍔°€備富绾跨▼鐨勬墽琛岃繃绋嬫槸涓€涓猼ick锛屾墍鏈夌殑寮傛浠诲姟閮芥槸閫氳繃浠诲姟闃熷垪涓€涓竴涓墽琛岀殑銆傛瘡涓换鍔¢兘瀛樺偍鍦ㄤ换鍔¢槦鍒椾腑銆傝鑼冭瀹氫换鍔″垎涓哄畯浠诲姟鍜屽井浠诲姟涓ょ被锛屾瘡涓畯浠诲姟缁撴潫鍚庡繀椤绘竻闄ゆ墍鏈夊井浠诲姟銆傜敤涓€娈典唬鐮佺洿瑙傚湴浠嬬粛浠诲姟鐨勬墽琛岄『搴忋€傚浜庯紙macroTaskQueue鐨刴acroTask锛墈handleMacroTask();for(microTaskQueue鐨刴icroTask){handleMicroTask(microTask);}}鍦ㄦ祻瑙堝櫒鐜涓嬶紝甯哥敤鐨勫畯浠诲姟鍒涘缓鏂规硶鏈塻etTimeout銆乻etInterval銆乸ostMessage銆丮essageChannel锛堥槦鍒椾紭鍏堜簬setTimeiout鎵ц锛夌綉缁滆姹侷O椤甸潰浜や簰锛欴OM銆侀紶鏍囥€侀敭鐩樸€佹粴鍔ㄤ簨浠堕〉闈㈡覆鏌撳父鐢ㄥ垱寤烘柟娉曞井浠诲姟Promise.thenMutationObserveprocess.nexttick涓殑nextTick鍑芥暟浣跨敤杩欎簺鏂规硶鏉ュ鐞嗗嚱鏁伴€氳繃鍙傛暟cb浼犲叆鐨勫紓姝ヤ换鍔°€?銆乶extTick鐨勫疄鐜板師鐞嗗皢浼犲叆鐨勫洖璋冨嚱鏁板寘瑁呮垚涓€涓紓姝ヤ换鍔°€傚紓姝ヤ换鍔″垎涓哄井浠诲姟鍜屽畯浠诲姟銆備负浜嗗敖蹇墽琛岋紝浼樺厛閫夋嫨寰换鍔★紱nextTick鎻愪緵浜嗗洓涓紓姝ユ柟娉昉romise.then銆丮utationObserver銆乻etImmediate銆乻etTimeOut(fn,0)3.1Vue.nextTick鍐呴儴閫昏緫鎵цinitGlobalAPI(Vue)鍒濆鍖朧ue鍏ㄥ眬API銆俈ue.nextTick鏄繖鏍峰畾涔夌殑锛歠unctioninitGlobalAPI(Vue){//...Vue.nextTick=nextTick;}鍙互鐪嬪嚭鐩存帴灏唍extTick鍑芥暟璧嬬粰Vue.nextTick闈炲父绠€鍗曘€?.2vm.$nextTick鐨勫唴閮ㄩ€昏緫Vue.prototype.$nextTick=function(fn){returnnextTick(fn,this)};鍙互鐪嬪嚭鍦╲m.$nextTick鍐呴儴涔熻皟鐢ㄤ簡nextTick鍑芥暟銆?.3婧愮爜瑙hnextTick婧愮爜浣嶄簬src/core/util/next-tick.jsnextTick婧愮爜涓昏鍒嗕负涓ら儴鍒嗭細import{noop}from'shared/util'import{handleError}from'./error'import{isIE,isIOS,isNative}from'./env'//涓婇潰涓夎涓庢牳蹇冧唬鐮佸叧绯讳笉澶э紝鐞嗚В鍗冲彲//noop琛ㄧず鏃犳搷浣滅殑绌哄嚱鏁帮紝鐢ㄤ綔鍑芥暟鐨勯粯璁ゅ€硷紝闃叉浼犲叆undefined瀵艰嚧閿欒//handleError閿欒澶勭悊鍑芥暟//isIE,isIOS,isNative鐜鍒ゆ柇鍑芥暟锛?/isNative鍒ゆ柇鏄惁鍘熺敓鏀寔锛屽鏋滄敮鎸佺涓夋柟鐨勮瘽锛屼細杩斿洖falseexportletisUsingMicroTask=false//nextTick鏈€缁堟槸鐢╩icrotask鎵ц鐨刢onstcallbacks=[]//瀛樺偍璋冪敤nextTick鏃朵紶鍏ョ殑鍥炶皟鍑芥暟letpending=false//琛ㄧずnextTick褰撳墠鏄惁姝e湪鎵ц锛屽彧鏈変竴涓竴娆℃墽琛?/澹版槑涓嬩竴涓猅ickfunction锛屾帴鏀朵竴涓洖璋冨嚱鏁板拰涓€涓墽琛屼笂涓嬫枃浣滀负鍙傛暟.push(()=>{if(cb){//灏濊瘯鎹曡幏浼犲叆鐨勫洖璋冮敊璇痗atchtry{cb.call(ctx)}catch(e){handleError(e,ctx,'nextTick')}}elseif(_resolve){_resolve(ctx)}})//濡傛灉褰撳墠涓嶅湪pe鎵惧埌鍥炶皟锛屾墽琛宼imeFunc鍑芥暟鍏堥€夋嫨褰撳墠鐜鏀寔鐨勫紓姝ユ柟娉?!cb&&typeofPromise!=='undefined'){returnnewPromise(resolve=>{_resolve=resolve})}}鍙互鐪嬪埌鍦╪extTick鍑芥暟涓紝瀵归€氳繃鍙傛暟cb浼犲叆鐨勫嚱鏁拌繘琛屼簡灏佽锛岀劧鍚巔ushedtocallbacks鐒跺悗鍦ㄦ暟缁勪腑浣跨敤鍙橀噺pending鏉ョ‘淇漷imerFunc()鍦ㄤ竴涓簨浠跺惊鐜腑鍙墽琛屼竴娆°€傛渶鍚庡鏋滄墽琛?!cb&&typeofPromise!=='undefined')锛屽垽鏂弬鏁癱b涓嶅瓨鍦紝娴忚鍣ㄦ敮鎸丳romise锛屽垯杩斿洖涓€涓狿romise绫荤殑瀹炰緥鍖栧璞°€傛瘮濡俷extTick().then(()=>{})锛屽綋_resolve鍑芥暟鎵ц鏃讹紝then閫昏緫灏变細鎵ц銆傝鎴戜滑鐪嬩竴涓媡imerFunc鍑芥暟鐨勫畾涔夈€傞鍏堬紝鎴戜滑鍙湅浣跨敤Promise鍒涘缓涓€涓紓姝ユ墽琛岀殑timerFunc鍑芥暟銆?/鍏堝垽鏂綋鍓嶇幆澧冩敮鎸佺殑寮傛鏂瑰紡锛屼紭鍏堥€夋嫨microtasks//Priority:Promise--->MutationObserver--->setImmediate--->setTimeout//setTimeOut鏈€灏忓欢鏃朵负4ms锛宻etImmediate浼氬湪main绾跨▼鎵ц瀹屽悗绔嬪嵆鎵ц//IE10鍜宯ode鏀寔setImmediate//澶氭璋冪敤nextTick鏃讹紝timerFunc鍙細鎵ц涓€娆ettimerFunc//鍒ゆ柇褰撳墠鐜鏄惁鏀寔promiseif(typeofPromise!=='undefined'&&isNative(Promise)){//鏀寔promiseconstp=Promise.resolve()timerFunc=()=>{//浣跨敤promise.then灏唂lushCallbacks鍑芥暟鍖呰鍒板紓姝ュ井浠诲姟p.then(flushCallbacks)if(isIOS)setTimeout(noop)}//鏍囪褰撳墠nextTick浣跨敤鐨刴icrotaskisUsingMicroTask=true//濡傛灉涓嶆敮鎸乸romise锛屽垽鏂槸鍚︽敮鎸丮utationObserver//涓嶆槸IE鐜锛孧utationObserver鏄ぉ鐢熺殑鏀寔锛岃繖涔熸槸涓€涓井浠诲姟}elseif(!isIE&&typeofMutationObserver!=='undefined'&&(isNative(MutationObserver)||MutationObserver.toString()==='[objectMutationObserverConstructor]')){letcounter=1//鏂板缓涓€涓狹utationObserver绫籧onstobserver=newMutationObserver(flushCallbacks)//鍒涘缓涓€涓枃鏈妭鐐筩onsttextNode=document.createTextNode(String(counter))//鐩戝惉杩欎釜鏂囨湰鑺傜偣锛屽綋鏁版嵁鍙樺寲鏃舵墽琛宖lushCallbacksobserver.observe(textNode,{characterData:true})timerFunc=()=>{counter=(counter+1)%2textNode.data=String(counter)//鏁版嵁鏇存柊}isUsingMicroTask=true//鏍囪褰撳墠nextTick浣跨敤鐨刴icrotask//鍒ゆ柇褰撳墠鐜鏄惁鍘熺敓鏀寔setImmediate}elseif(typeofsetImmediate!=='undefined'&&isNative(setImmediate)){timerFunc=()=>{setImmediate(flushCallbacks)}}else{//濡傛灉浠ヤ笂涓変釜閫夐」閮戒笉鏀寔锛屽垯閫夋嫨setTimeouttimerFunc=()=>{setTimeout(flushCallbacks,0)}}isNative鏂规硶鏄浣曞畾涔夌殑锛熶唬鐮佸涓嬶細functionisNative(Ctor){returntypeofCtor==='function'&&/nativecode/.test(Ctor.toString())}鍦ㄩ噷闈㈡壘鍒皌imerFunc鍑芥暟灏辨槸璋冪敤flushCallbacks鍑芥暟鐢ㄥ悇绉嶅紓姝ユ墽琛屾柟寮忋€傛垜浠湅涓€涓媐lushCallbacks鍑芥暟//濡傛灉澶氭璋冪敤nextTick锛屼細渚濇鎵ц涓婇潰鐨勬柟娉曪紝骞跺皢nextTick鍥炶皟鏀惧埌callbacks鏁扮粍涓?/鏈€鍚庯紝flushCallbacks鍑芥暟浼氶亶鍘哻allbacks鏁扮粍骞舵墽琛屽洖璋冨嚱鏁癴lushCallbacks(){pending=falseconstcopies=callbacks.slice(0)//澶嶅埗callbacks.length=0//clearcallbacksfor(leti=0;i