精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從Javascript 事件循環看 Vue.nextTick 的原理和執行機制

開發 前端
Vue 的特點之一就是響應式,但是有些時候數據更新了,我們看到頁面上的 DOM 并沒有立刻更新。如果我們需要在 DOM 更新之后再執行一段代碼時,可以借助 nextTick 實現。

拋磚引玉

Vue 的特點之一就是響應式,但是有些時候數據更新了,我們看到頁面上的 DOM 并沒有立刻更新。如果我們需要在 DOM 更新之后再執行一段代碼時,可以借助 nextTick 實現。

[[323732]]

我們先來看一個例子

  1. export default { 
  2.   data() { 
  3.     return { 
  4.       msg: 0 
  5.     } 
  6.   }, 
  7.   mounted() { 
  8.     this.msg = 1 
  9.     this.msg = 2 
  10.     this.msg = 3 
  11.   }, 
  12.   watch: { 
  13.     msg() { 
  14.       console.log(this.msg) 
  15.     } 
  16.   } 

這里的結果是只輸出一個 3,而非依次輸出 1,2,3。這是為什么呢?

vue 的官方文檔是這樣解釋的:

Vue 異步執行 DOM 更新。只要觀察到數據變化,Vue 將開啟一個隊列,并緩沖在同一事件循環中發生的所有數據改變。如果同一個watcher 被多次觸發,只會被推入到隊列中一次。這種在緩沖時去除重復數據對于避免不必要的計算和 DOM 操作上非常重要。然后,在下一個的事件循環“tick”中,Vue 刷新隊列并執行實際 (已去重的) 工作。Vue 在內部嘗試對異步隊列使用原生的Promise.then和 MessageChannel,如果執行環境不支持,會采用setTimeout(fn, 0)代替。

假如有這樣一種情況,mounted鉤子函數下一個變量 a 的值會被++循環執行 1000 次。每次++時,都會根據響應式觸發setter->Dep->Watcher->update->run。如果這時候沒有異步更新視圖,那么每次++都會直接操作 DOM 一次,這是非常消耗性能的。所以 Vue 實現了一個queue隊列,在下一個 Tick(或者是當前 Tick 的微任務階段)的時候會統一執行queue中Watcher的run。同時,擁有相同 id 的Watcher不會被重復加入到該queue中去,所以不會執行 1000 次Watcher的run。最終的結果是直接把 a 的值從 1 變成 1000,大大提升了性能。

在 vue 中,數據監測都是通過Object.defineProperty來重寫里面的 set 和 get 方法實現的,vue 更新 DOM 是異步的,每當觀察到數據變化時,vue 就開始一個隊列,將同一事件循環內所有的數據變化緩存起來,等到下一次 eventLoop,將會把隊列清空,進行 DOM 更新。

想要了解 vue.nextTick 的執行機制,我們先來了解一下 javascript 的事件循環。

js 事件循環

js 的任務隊列分為同步任務和異步任務,所有的同步任務都是在主線程里執行的。異步任務可能會在 macrotask 或者 microtask 里面,異步任務進入 Event Table 并注冊函數。當指定的事情完成時,Event Table 會將這個函數移入 Event Queue。主線程內的任務執行完畢為空,會去 Event Queue 讀取對應的函數,進入主線程執行。上述過程會不斷重復,也就是常說的 Event Loop(事件循環)。

1. macro-task(宏任務):

每次執行棧執行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調并放到執行棧中執行)。瀏覽器為了能夠使得 js 內部(macro)task與 DOM 任務能夠有序執行,會在一個(macro)task執行結束后,在下一個(macro)task執行開始前,對頁面進行重新渲染。宏任務主要包含:

  • script(整體代碼)
  • setTimeout / setInterval
  • setImmediate(Node.js 環境)
  • I/O
  • UI render
  • postMessage
  • MessageChannel

2. micro-task(微任務):

可以理解是在當前 task 執行結束后立即執行的任務。也就是說,在當前 task 任務后,下一個 task 之前,在渲染之前。所以它的響應速度相比 setTimeout(setTimeout 是 task)會更快,因為無需等渲染。也就是說,在某一個 macrotask 執行完后,就會將在它執行期間產生的所有 microtask 都執行完畢(在渲染前)。microtask 主要包含:

  • process.nextTick(Node.js 環境)
  • Promise
  • Async/Await
  • MutationObserver(html5 新特性)

3. 小結

  • 先執行主線程
  • 遇到宏隊列(macrotask)放到宏隊列(macrotask)
  • 遇到微隊列(microtask)放到微隊列(microtask)
  • 主線程執行完畢
  • 執行微隊列(microtask),微隊列(microtask)執行完畢
  • 執行一次宏隊列(macrotask)中的一個任務,執行完畢
  • 執行微隊列(microtask),執行完畢
  • 依次循環。。。

Vue.nextTick 源碼

vue 是采用雙向數據綁定的方法驅動數據更新的,雖然這樣能避免直接操作 DOM,提高了性能,但有時我們也不可避免需要操作 DOM,這時就該 Vue.nextTick(callback)出場了,它接受一個回調函數,在 DOM 更新完成后,這個回調函數就會被調用。不管是 vue.nextTick 還是vue.prototype.\$nextTick 都是直接用的nextTick這個閉包函數。

  1. export const nextTick = (function () { 
  2.   const callbacks = [] 
  3.   let pending = false 
  4.   let timerFunc 
  5.  
  6.   function nextTickHandler () { 
  7.     pending = false 
  8.     const copies = callbacks.slice(0) 
  9.     callbacks.length = 0 
  10.     for (let i = 0; i < copies.length; i++) { 
  11.       copies[i]() 
  12.     } 
  13.   } 
  14.  ... 
  15. })() 

使用數組callbacks保存回調函數,pending表示當前狀態,使用函數nextTickHandler 來執行回調隊列。在該方法內,先通過slice(0)保存了回調隊列的一個副本,通過設置 callbacks.length = 0清空回調隊列,最后使用循環執行在副本里的所有函數。

  1. if (typeof Promise !== 'undefined' && isNative(Promise)) { 
  2.   var p = Promise.resolve() 
  3.   var logError = err => { 
  4.     console.error(err) 
  5.   } 
  6.   timerFunc = () => { 
  7.     p.then(nextTickHandler).catch(logError) 
  8.     if (isIOS) setTimeout(noop) 
  9.   } 
  10. } else if (typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]')) { 
  11.   var counter = 1 
  12.   var observer = new MutationObserver(nextTickHandler) 
  13.   var textNode = document.createTextNode(String(counter)) 
  14.   observer.observe(textNode, { 
  15.     characterData: true 
  16.   }) 
  17.   timerFunc = () => { 
  18.     counter = (counter + 1) % 2 
  19.     textNode.data = String(counter) 
  20.   } 
  21. } else { 
  22.   timeFunc = () => { 

隊列控制的最佳選擇是microtask,而microtask的最佳選擇是Promise。但如果當前環境不支持 Promise,就檢測到瀏覽器是否支持 MO,是則創建一個文本節點,監聽這個文本節點的改動事件,以此來觸發nextTickHandler(也就是 DOM 更新完畢回調)的執行。此外因為兼容性問題,vue 不得不做了microtask向macrotask 的降級方案。

為讓這個回調函數延遲執行,vue 優先用promise來實現,其次是 html5 的 MutationObserver,然后是setTimeout。前兩者屬于microtask,后一個屬于 macrotask。下面來看最后一部分。

  1. return function queueNextTick(cb?: Function, ctx?: Object) { 
  2.   let _resolve 
  3.   callbacks.push(() => { 
  4.     if (cb) cb.call(ctx) 
  5.     if (_resolve) _resolve(ctx) 
  6.   }) 
  7.   if (!pending) { 
  8.     pending = true 
  9.     timerFunc() 
  10.   } 
  11.   if (!cb && typeof Promise !== 'undefined') { 
  12.     return new Promise(resolve => { 
  13.       _resolve = resolve 
  14.     }) 
  15.   } 

這就是我們真正調用的nextTick函數,在一個event loop內它會將調用 nextTick的cb 回調函數都放入 callbacks 中,pending 用于判斷是否有隊列正在執行回調,例如有可能在 nextTick 中還有一個 nextTick,此時就應該屬于下一個循環了。最后幾行代碼是 promise 化,可以將 nextTick 按照 promise 方式去書寫(暫且用的較少)。

應用場景

場景一、點擊按鈕顯示原本以 v-show = false 隱藏起來的輸入框,并獲取焦點。

  1. <input id="keywords" v-if="showit"> 
  2.  
  3. showInput(){ 
  4.   this.showit = true 
  5.   document.getElementById("keywords").focus() 

以上的寫法在第一個 tick 里,因為獲取不到輸入框,自然也獲取不到焦點。如果我們改成以下的寫法,在 DOM 更新后就可以獲取到輸入框焦點了。

  1. showsou(){ 
  2.   this.showit = true 
  3.   this.$nextTick(function () { 
  4.     // DOM 更新了 
  5.     document.getElementById("keywords").focus() 
  6.   }) 

場景二、獲取元素屬,點擊獲取元素寬度。

  1. <div id="app"> 
  2.   <p ref="myWidth" v-if="showMe">{{ message }}</p> 
  3.   <button @click="getMyWidth">獲取p元素寬度</button> 
  4. </div> 
  5.  
  6. getMyWidth() { 
  7.   this.showMe = true
  8.   thisthis.message = this.$refs.myWidth.offsetWidth; 
  9.   //報錯 TypeError: this.$refs.myWidth is undefined 
  10.   this.$nextTick(()=>
  11.       //dom元素更新后執行,此時能拿到p元素的屬性 
  12.     thisthis.message = this.$refs.myWidth.offsetWidth; 
  13.   }) 

 

責任編輯:趙寧寧 來源: 前端先鋒隊
相關推薦

2020-09-21 14:35:20

VuenextTick前端

2017-09-12 09:50:08

JavaScriptEvent LoopVue.js

2017-02-09 15:15:54

Chrome瀏覽器

2024-08-26 14:52:58

JavaScript循環機制

2016-09-06 21:23:25

JavaScriptnode異步

2021-10-15 09:56:10

JavaScript異步編程

2020-12-29 08:21:03

JavaScript微任務宏任務

2010-07-16 09:00:20

開源RedOffice紅旗2000

2017-07-27 16:31:11

2015-09-21 14:20:35

2024-06-21 08:32:24

2021-01-18 08:24:51

JavaScriptMicrotask微任務

2024-09-20 05:46:00

2017-06-29 09:15:36

推薦算法策略

2022-04-25 09:03:16

JavaScript代碼

2009-03-17 15:36:29

JavaScript循環事件

2025-05-09 01:30:00

JavaScript事件循環基石

2021-12-08 07:55:41

EventLoop瀏覽器事件

2022-09-19 19:51:30

ReactuseEffect

2022-07-07 09:12:17

JavaScript線程循環機制
點贊
收藏

51CTO技術棧公眾號

国产精品高潮在线| 日韩欧美你懂的| 久久亚洲综合网| 国产在线一级片| 日本一二区不卡| 欧美精品日韩精品| 隔壁人妻偷人bd中字| 十九岁完整版在线观看好看云免费| 久久久久网站| 久久夜精品va视频免费观看| 制服丝袜第一页在线观看| 校园春色亚洲| 国产精品第一页第二页第三页| 95av在线视频| 中文字幕一区二区三区精品| av亚洲免费| 精品美女一区二区| 亚洲色图久久久| 欧美女同一区| 国产欧美一区二区精品性色超碰| 亚洲最大av网| 无码人妻熟妇av又粗又大| 中文字幕乱码亚洲无线精品一区| 亚洲精品久久久久久久久久久久| 成 人 黄 色 小说网站 s色| 国产免费拔擦拔擦8x高清在线人| 国产精品久久久久久久久果冻传媒| 国产二区一区| 亚洲综合视频在线播放| 国产视频一区在线观看一区免费| 日韩一区二区av| av无码av天天av天天爽| 久久天堂久久| 欧美亚洲综合在线| 国产一区二区视频播放| 黄色小网站在线观看| 久久综合五月天婷婷伊人| 亚洲一区制服诱惑| 久久精品偷拍视频| 国产亚洲在线| 欧美极品美女视频网站在线观看免费| 青青青视频在线免费观看| 亚洲日产av中文字幕| 精品少妇一区二区三区在线播放| 中日韩av在线播放| 亚洲成人激情社区| 91亚洲精品| 欧美电影免费| 亚洲色图25p| 李丽珍裸体午夜理伦片| 99久热在线精品视频观看| 在线观看一区二区视频| 日韩欧美精品在线观看视频| heyzo高清国产精品| 亚洲欧美国产高清| 最近看过的日韩成人| 中文字幕在线视频区| 久久久综合视频| 久久国产一区二区| 天堂在线资源网| 成人午夜免费视频| 动漫精品视频| 亚洲h视频在线观看| 国产精品中文字幕欧美| 91九色国产在线| 91肉色超薄丝袜脚交一区二区| 日本午夜一本久久久综合| 国产91在线高潮白浆在线观看| 久久99精品波多结衣一区| 99在线|亚洲一区二区| 97在线看免费观看视频在线观看| 国产一级生活片| 国产一区美女| 国产做受69高潮| 国产精彩视频在线| 99综合在线| 日本午夜在线亚洲.国产| 久久精品无码av| 日韩精品午夜视频| 国产欧洲精品视频| 国产精品久久久久久免费 | 超碰在线网站| 性欧美疯狂xxxxbbbb| 国产精品免费入口| 九九热线视频只有这里最精品| 欧美午夜一区二区| 国产精欧美一区二区三区白种人| 国产日韩中文在线中文字幕| 日韩欧美三级在线| 青青草成人免费视频| 国产一区2区| 久久精品国产精品| 久久精品国产av一区二区三区| 国产欧美在线| 国产欧亚日韩视频| 亚洲大尺度视频| 久久先锋影音av鲁色资源网| 亚洲激情一区二区| 超碰人人在线| 欧美日韩一区免费| www.99r| 91久久偷偷做嫩草影院电| 亚洲成人久久久| www.av欧美| 欧美一区91| 欧美最顶级的aⅴ艳星| 一区二区视频在线免费观看| 国产精品888| 欧美精品一区二区三区在线看午夜| 在线观看美女网站大全免费| 一区二区三区日本| 黄色av免费在线播放| 国产一区精品二区| 日韩精品视频在线观看网址| 午夜国产福利视频| 国产亚洲在线观看| 成人高清视频观看www| 天天色天天操天天射| 国产精品亲子伦对白| 男人插女人视频在线观看| 欧美日一区二区三区| 亚洲第一色在线| 女同久久另类69精品国产| 亚洲精品一级| 91精品综合久久久久久五月天| 嫩草在线播放| 亚洲午夜久久久久| 自拍偷拍一区二区三区四区| 国产96在线亚洲| 久久久国产精品一区| 日本高清不卡码| 成人免费视频视频在线观看免费| 一区二区三区精品国产| 桃色一区二区| 亚洲国产精品va在线看黑人动漫| 91香蕉一区二区三区在线观看| 久久久精品网| 国产一区在线免费观看| 成人短视频在线| 欧美亚洲一区三区| aaaaa级少妇高潮大片免费看| 红桃视频亚洲| 亚洲qvod图片区电影| 亚洲精品承认| 在线精品视频免费播放| 香蕉视频黄色在线观看| 在线免费高清一区二区三区| 91久久久精品| 亚洲精品承认| 欧美三级中文字| 亚洲成人黄色av| 亚洲一区中文| 精品欧美日韩在线| mm视频在线视频| 日韩欧美一级精品久久| www.5588.com毛片| 精品制服美女丁香| 中文字幕av久久| 亚洲色图图片| 久久人人爽人人爽爽久久| 中国一级片黄色一级片黄| 久久精品一区二区| 亚洲国产精品毛片av不卡在线| 欧美高清视频看片在线观看| 97免费视频在线播放| 天天操天天射天天| 精品久久久久久久久久久久| 中文字幕在线永久| 中日韩男男gay无套| 黄色99视频| 午夜久久中文| 亚洲视频777| 天天操天天干天天摸| 中文一区在线播放| 性欧美在线视频| 欧美福利电影在线观看| 91偷拍精品一区二区三区| 欧洲中文在线| 亚洲精品av在线| 国产一级片毛片| 国产亚洲一二三区| 欧美日韩一区二区三区69堂| 亚洲综合中文| 国产精品国产精品| 欧美成人性网| 日韩中文字幕视频在线| 国产绿帽一区二区三区| 亚洲一区成人在线| 久久精品国产亚洲av麻豆| 日韩成人精品在线观看| 热这里只有精品| 国产美女撒尿一区二区| 日本高清久久天堂| 欧美高清视频| 精品国产网站在线观看| 黄色片网站在线免费观看| 国产精品欧美久久久久一区二区| 国产探花一区二区三区| 亚洲一区二区三区免费在线观看| 亚洲精品在线视频观看| 99re6热只有精品免费观看| 日韩av大片免费看| 国产区在线看| 亚洲欧美变态国产另类| 99草在线视频| 欧美视频13p| 成人免费视频国产免费观看| av高清久久久| 污污网站免费观看| 亚洲主播在线| 亚洲一区 在线播放| 香蕉久久夜色精品国产更新时间 | 欧美黄色一级网站| 久久先锋影音av鲁色资源| 宇都宫紫苑在线播放| 久久精品1区| 可以在线看黄的网站| 欧美猛男男男激情videos| av免费观看久久| 69堂精品视频在线播放| 午夜精品理论片| 国产美女在线观看| 在线亚洲男人天堂| 天堂成人在线| 精品国产乱码久久久久久久| 丰满人妻一区二区三区四区| 亚洲1区2区3区4区| 久久好看免费视频| 狠狠人妻久久久久久综合蜜桃| 青青草国产精品97视觉盛宴| 国产黄色激情视频| 一区二区视频免费| 日韩美女视频一区二区| 老司机福利av| 懂色一区二区三区免费观看| 日本中文字幕精品—区二区| 亚洲在线视频| 国产a级片网站| 中文字幕一区二区三区乱码图片| 欧美日韩成人一区二区三区| 国产精品15p| 97久久人人超碰caoprom欧美| 日韩五码电影| 国产精品大片wwwwww| 五月天av在线| 97人人做人人爱| 黄页在线观看免费| 欧美成人在线免费| 日本在线看片免费人成视1000| 亚洲网址你懂得| 伦理片一区二区三区| 亚洲级视频在线观看免费1级| 亚洲黄色小说网| 日韩免费视频一区| 国产三级三级在线观看| 51午夜精品国产| 亚洲一区二区激情| 欧美日韩激情一区二区三区| 在线亚洲欧美日韩| 欧美久久一二三四区| 国产一区二区在线视频聊天| 欧美女孩性生活视频| 一级片在线观看视频| 欧美日韩小视频| 一区二区三区黄色片| 欧美日韩国产首页| 国产一区二区自拍视频| 亚洲天堂美女视频| 一个色综合网| 成年人黄色在线观看| 色琪琪久久se色| 亚洲免费av网| 综合久久久久| 菠萝蜜视频在线观看入口| 欧美精品日韩| 男女视频网站在线观看| 日韩午夜在线| 免费裸体美女网站| 日本sm残虐另类| 992kp快乐看片永久免费网址| 青青国产91久久久久久| 日本不卡一区二区在线观看| 激情五月播播久久久精品| 色哟哟免费视频| 99精品在线免费| 先锋影音av在线| 亚洲欧美自拍偷拍色图| 久草视频在线资源站| 欧美日韩亚洲视频| 中文字幕乱码人妻二区三区| 91精品国产入口| 国产伦理一区| 久久另类ts人妖一区二区| 在线亚洲a色| 一区二区三区四区| 欧美激情综合| 人妻有码中文字幕| 中文字幕久久精品一区二区| 亚洲欧美在线一区二区| 国产精品一区在线看| 久久视频在线看| 丁香花视频在线观看| 亚洲av无码国产精品久久| 蜜桃传媒麻豆第一区在线观看| 亚洲高清在线不卡| av成人免费在线| 国产一二三四区在线| 亚洲靠逼com| 在线视频一区二区三区四区| 欧美另类久久久品| 亚洲色图 校园春色| 日韩网站在线观看| 97超碰免费在线| 国产精品久久久久久久午夜| 亚洲一区二区三区免费| 婷婷久久五月天| 精品成人免费| 中文字幕国产免费| 99re视频这里只有精品| 中文字幕无码日韩专区免费| 欧美日韩亚洲91| 99精品在线看| 亚洲欧美日韩网| 国产福利在线免费观看| 国产女同一区二区| 亚洲精品无吗| 青青视频免费在线| 蜜臀久久99精品久久久久宅男| 给我看免费高清在线观看| 亚洲女性喷水在线观看一区| 中文人妻熟女乱又乱精品| 日韩av最新在线| 人交獸av完整版在线观看| 国产精品一区二区久久久| 欧美激情在线免费| 成年人网站免费视频| 国产成人av自拍| 日韩国产第一页| 欧美三级日本三级少妇99| 凸凹人妻人人澡人人添| 欧美高清不卡在线| 日韩精品免费视频一区二区三区 | 欧美一区二区三区在线观看视频 | 欧洲成人一区| 久久综合中文色婷婷| 一区二区的视频| 不卡一卡二卡三乱码免费网站| 亚洲欧美精品aaaaaa片| 欧美日韩一二三区| a天堂中文在线| 国产成人+综合亚洲+天堂| 亚洲春色h网| 欧美 日韩精品| 91在线视频18| 国产成人精品一区二三区| 亚洲第一区第二区| av在线中出| 国产美女99p| 精品成人国产| 欧美深性狂猛ⅹxxx深喉| 亚洲一区二区三区四区五区黄| 亚洲第一精品网站| 久久久久久久网站| 久久99国产精品久久99大师| 久草视频这里只有精品| 国产成人免费在线观看| 国产一级理论片| 亚洲成人网在线| 波多野结衣中文在线| 国产一区国产精品| 午夜在线一区| 香蕉视频黄色在线观看| 在线观看成人小视频| 77777影视视频在线观看| 91精品免费久久久久久久久| 欧美顶级大胆免费视频| 日本一二三区在线| 亚洲综合一二区| 香蕉视频黄色片| 国产精品电影网| 亚洲精品99| 一边摸一边做爽的视频17国产 | 日韩亚洲不卡在线| 免费人成在线不卡| 国产国语性生话播放| 在线看不卡av| av片在线观看永久免费| 国产伦精品一区二区三区四区免费 | 8x8x华人在线| 99这里只有久久精品视频| 天堂网一区二区| 久久躁日日躁aaaaxxxx| 999国产精品一区| 日韩久久一级片| 国产精品免费av| 亚洲av无码专区在线| 欧洲精品久久久| 99热在线成人| 制服丝袜第一页在线观看| 欧美精品videos另类|