成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

解析$nextTick魔力,為啥大家都愛它?

開發 前端
$nextTick 并不是一個真正意義上的微任務microtask,而是利用了事件循環機制來實現異步更新。因此,它的執行時機相對于微任務可能會有所延遲,但仍能保證在 DOM 更新后盡快執行回調函數。

1.為什么需要使用$nextTick?

首先我們來看看官方對于$nextTick的定義:

在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。

由于vue的試圖渲染是異步的,生命周期的created()鉤子函數進行的DOM操作一定要放在Vue.nextTick()的回調函數中,原因是在created()鉤子函數執行的時候DOM其實并未進行渲染,而此時進行DOM操作是徒勞的,所以一定要將DOM操作的js代碼放到Vue.nextTick()的回調函數中。除了在created()鉤子函數中使用之外咱們還會遇到很多種需要使用到Vue.nextTick()的場景,如下所示:

咱們日常生活中常常會遇上上述場景,當我們點擊按鈕更新數據時候,如下示例:

<template>
    <div>
     <input type="text" v-if = "isShow" ref="input"/>
     <button @click="handleClick">點擊顯示輸入框,并且獲取輸入框焦點</button>
   </div>
</template>
<script>
export default {
 data() {
     return {
         isShow: false 
      }
 },
 methods : {
 handleClick () {
     this.isShow = true
     this.$refs.input.focus() //控制欄會報錯,因為還沒有這個dom    
    }
  }
}
</script>

點擊控制欄顯示效果:控制欄報錯,提示沒有獲取到dom元素;

所以現在Vue.nextTick()派上了用場,Vue.nextTick() 方法的作用正是等待上一次事件循環執行完畢,并在下一次事件循環開始時再執行回調函數。這樣可以保證回調函數中的 DOM 操作已經被 Vue.js 進行過更新,從而避免了一些潛在的問題,如下代碼所示:

<template>
  <div>
    <input type="text" v-if = "isShow" ref="input"/>
    <button @click="handleClick">點擊顯示輸入框,并且獲取輸入框焦點</button>
  </div>
</template>
<script>
export default {
 data() {
   return {
     isShow: false
   }
 },
 methods : {
   handleClick () {
     this.isShow = true
     this.$nextTick(()=>{
       this.$refs.input.focus() 
     })
 
   }
 }
}
</script>

加上this.$nextTick后就能夠使得輸入框獲取到焦點;

總而言之Vue.nextTick()就是下次 DOM 更新渲染后執行延遲回調函數。在日常開發中,我們在修改數據之后使用這個方法,就可以獲取更新后的 DOM的同時進行在對DOM進行相對應操作的 js代碼;

2.$nextTick如何實現的?

JS是單線程執行的,所有的同步任務都是在主線程上執行的,形成了一個執行棧,從上到下依次執行,異步代碼會放在任務隊列里面。

?同步任務

在主線程里執行,當瀏覽器第一遍過濾html文件的時候可以執行完;(在當前作用域直接執行的所有內容,包括執行的方法、new出來的對象)

?異步任務

耗費時間較長或者性能較差的,瀏覽器執行到這些的時候會將其丟到異步任務隊列中,不會立即執行

同時異步任務分為宏任務(如setTimeout、setInterval、postMessage、setImmediate等)和微任務(Promise、process.nextTick等),瀏覽器執行這兩種任務的優先級不同;會優先執行微任務隊列的代碼,微任務隊列清空之后再執行宏任務的隊列,這樣循環往復;

JS自上向下進行代碼的編譯執行,遇到同步代碼壓入JS執行棧執行后出棧,遇到異步代碼放入任務隊列,當JS執行棧清空,去執行異步隊列中的回調函數,先去執行微任務隊列,當微任務隊列清空后,去檢測執行宏任務隊列中的回調函數,直至所有棧和隊列清空

整體流程如下圖所示:

接下來讓我們看看nextTick的源碼~

vue將nextTick的源碼放在了vue/core/util/next-tick.js中。如下圖所示:

我們把這個文件拆成三個部分來看:

1.nextTick定義函數

我們將nextTick函數單獨拿出來,callbacks是一個回調隊列,其實調用nextTick就是往這個數組里面傳執行任務,callbacks新增回調函數之后執行timerFunc函數,pending是用來限制同一個事件循環內只能執行一次的pending鎖;

const callbacks = [] // 回調隊列
let pending = false // 
export function nextTick (cb?: Function, ctx?: Object) {
 let _resolve
 callbacks.push(() => {
  // cb 回調函數會經統一處理壓入 callbacks 數組
     if (cb) {
         try {
             cb.call(ctx)
         } catch (e) {
             handleError(e, ctx, 'nextTick')
         }
     } else if (_resolve) {
         _resolve(ctx)
        }
     })
  // 執行異步延遲函數 timerFunc
     if (!pending) {
     pending = true
     timerFunc()
 }
 // $flow-disable-line
 // 當 nextTick 沒有傳入函數參數的時候,返回一個 Promise 化的調用
if (!cb && typeof Promise !== 'undefined') {
     return new Promise(resolve => {
     _resolve = resolve
     })
 }
}

2.timerFunc函數

 做了四個判斷,先后嘗試當前環境是否能夠使用原生的Promise.then、MutationObserver和setImmediate,不斷的降級處理,如果以上三個都不支持,則最后就會直接使用setTimeOut,主要操作就是將flushCallbacks中的函數放入微任務或者宏任務,等待下一個事件循環開始執行;宏任務耗費的時間是大于微任務的,所以在瀏覽器支持的情況下,優先使用微任務。如果瀏覽器不支持微任務,使用宏任務;但是,各種宏任務之間也有效率的不同,需要根據瀏覽器的支持情況,使用不同的宏任務;

export let isUsingMicroTask = false
let timerFunc
if (typeof Promise !== 'undefined' && isNative(Promise)) {
 //是否支持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]'
)) {
//是否支持MutationObserver 
 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
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
 timerFunc = () => {
  //是否支持setImmediate
 setImmediate(flushCallbacks)
 }
} else {
 // Fallback to setTimeout.
 timerFunc = () => {
  //上面都不行,直接使用setTimeout
 setTimeout(flushCallbacks, 0)
 }
}

3.flushCallbacks函數

flushCallbacks函數只有幾行,也很好理解,將pending鎖置為false,同時將callbacks數組復制一份之后再將callbacks置為空,接下來將復制出來的callbacks數組的每個函數依次進行執行,簡單來說它的主要作用就是用來執行callbacks中的回調函數;

function flushCallbacks () {
 pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
     copies[i]()
 }
}

值得注意的是,$nextTick 并不是一個真正意義上的微任務microtask,而是利用了事件循環機制來實現異步更新。因此,它的執行時機相對于微任務可能會有所延遲,但仍能保證在 DOM 更新后盡快執行回調函數。

總的來說,nextTick就是

1.將傳入的回調函數放入callbacks數組等待執行,定義pending判斷鎖保證一個事件循環中只能調用一次timerFunc函數;

2.根據環境判斷使用異步方式,調用timerFunc函數調用flushCallbacks函數依次執行callbacks中的回調函數;

3.個人小結

nextTick可避免數據更新后導致DOM的數據不一致的問題,提供了更穩定的異步更新機制,解決了created鉤子函數DOM未渲染會造成的異步數據渲染問題,但如果過多的使用nextTick會導致事件循環中任務數量和回調函數增多,有可能出現可怕的回調地獄,導致性能下降,同時過度依賴nextTick也會降低代碼的可讀性,所以大家還是"按需加載"的好~

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2017-12-07 15:00:00

筆記本OLED屏幕

2014-03-06 09:42:25

無線技術802.11ac

2022-12-29 11:45:52

人貨匹配模型電子商務

2022-04-08 10:15:29

VueReacHooks

2025-04-02 01:20:00

阻塞隊列源碼

2024-04-16 09:53:56

PostgreSQL數據庫優化索引

2012-05-07 14:24:15

HTML 5Web App

2012-05-28 13:09:12

HTML5

2024-10-24 09:18:45

2025-03-10 07:10:00

2019-12-12 10:02:29

滴滴數據中臺

2021-12-21 15:31:40

KubernetesDocker容器

2018-07-25 16:01:07

2019-12-04 17:49:11

戴爾

2013-02-22 09:43:41

面向對象面向對象編程

2017-07-25 12:42:23

互聯網

2024-09-20 05:46:00

2020-08-05 07:53:53

程序員網站技術

2021-02-02 07:37:39

NextTickvueDOM
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲黄色av网站 | 国产精品无码专区在线观看 | 日韩精品中文字幕在线 | 成人影院一区二区三区 | 男女羞羞在线观看 | 亚洲欧美日本在线 | 日本精品免费 | 在线播放精品视频 | 亚洲精品国产电影 | 久久久综合色 | 亚洲天堂二区 | 免费的av网站 | 欧美一区二区三区大片 | 在线观看中文字幕 | 91在线精品秘密一区二区 | 欧美色视频免费 | 国产精品一区视频 | 日本人做爰大片免费观看一老师 | 一级大片| 免费观看一区二区三区毛片 | 情侣黄网站免费看 | 在线观看中文字幕视频 | 午夜影院在线观看版 | 91tv在线观看 | 激情国产 | 精品一二区 | 日韩精品成人 | 亚洲视频免费在线播放 | 视频一区二区三区中文字幕 | 日韩精品一区二区三区视频播放 | 涩涩视频在线播放 | av网站在线播放 | 天天操天天天干 | 欧美日韩中文在线 | 精品一区二区三区在线观看国产 | 性欧美精品一区二区三区在线播放 | 国产精品一区三区 | 欧美成人h版在线观看 | 精品国产一区二区国模嫣然 | 一本色道久久综合亚洲精品高清 | 日本精品视频一区二区三区四区 |