欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

從源碼里了解vue中的nextTick的使用

 更新時(shí)間:2018年11月22日 08:34:14   作者:大雄沒(méi)了哆啦A夢(mèng)  
這篇文章主要介紹了vue的nextTick的使用,本文從源碼出發(fā)給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

今天做了一個(gè)需求,場(chǎng)景是這樣的:

在頁(yè)面拉取一個(gè)接口,這個(gè)接口返回一些數(shù)據(jù),這些數(shù)據(jù)是這個(gè)頁(yè)面的一個(gè)浮層組件要依賴的,然后我在接口一返回?cái)?shù)據(jù)就展示了這個(gè)浮層組件,展示的同時(shí),上報(bào)一些數(shù)據(jù)給后臺(tái)(這些數(shù)據(jù)就是父組件從接口拿的),這個(gè)時(shí)候,神奇的事情發(fā)生了,雖然我拿到數(shù)據(jù)了,但是浮層展現(xiàn)的時(shí)候,這些數(shù)據(jù)還未更新到組件上去。

父組件:

<template>
  .....
  <pop ref="pop" :name="name"/>
</template>
<script>
export default {
  .....
  created() {
    ....
    // 請(qǐng)求數(shù)據(jù),并從接口獲取數(shù)據(jù)
    Data.get({
      url: xxxx,
      success: (data) => {
        // 問(wèn)題出現(xiàn)在這里,我們賦值以后直接調(diào)用show方法,去展現(xiàn),show方法調(diào)用的同時(shí)上報(bào)數(shù)據(jù),而上報(bào)的數(shù)據(jù)這個(gè)時(shí)候還未更新到子組件
        this.name = data.name
        this.$refs.pop.show()
      }
    })
  }
}
</script>

子組件

<template>
  <div v-show="isShow">
    ......
  </div>
</template>
<script>
export default {
  .....
  props: ['name'],
  methods: {
    show() {
      this.isShow = true
      // 上報(bào)
      Report('xxx', {name: this.name})
    }
  }
}
</script>

問(wèn)題分析:

原因vue官網(wǎng)上有解析( cn.vuejs.org/v2/guide/re… )

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

這句話就是說(shuō),當(dāng)我們?cè)诟附M件設(shè)置this.name=name的時(shí)候,vue并不會(huì)直接更新到子組件中(dom的更新也一樣未立即執(zhí)行),而是把這些更新操作全部放入到一個(gè)隊(duì)列當(dāng)中,同個(gè)組件的所有這些賦值操作,都作為一個(gè)watcher的更新操作放入這個(gè)隊(duì)列當(dāng)中,然后等到事件循環(huán)結(jié)束的時(shí)候,一次性從這個(gè)隊(duì)列當(dāng)中獲取所有的wathcer執(zhí)行更新操作。在我們這個(gè)例子當(dāng)中,就是我們?cè)谡{(diào)用show的時(shí)候,實(shí)際上,我們的this.name=name并未真正執(zhí)行,而是被放入隊(duì)列中。vue的這種做法是基于優(yōu)化而做的,毋庸置疑,不然我們?nèi)绻衝多個(gè)賦值vue就執(zhí)行n多個(gè)dom更新,那效率將會(huì)非常的低效和不可取的。


下文中的更新操作指對(duì)data的值進(jìn)行更新的操作,在vue中,都會(huì)被放入隊(duì)列異步執(zhí)行。

解決方案:

1、 使用nextTick來(lái)延遲執(zhí)行show方法(籠統(tǒng)得說(shuō),執(zhí)行所有需要在數(shù)據(jù)真正更新后的操作

通過(guò)上面的分析我們知道,我們的所有的對(duì)vue實(shí)例的更新操作,都會(huì)先被放入一個(gè)隊(duì)列當(dāng)中,延遲異步執(zhí)行,這些異步操作,要么是microtask,要么是macrotask(是microtask還是macroktask取決于環(huán)境,nextTick的源碼中有所體現(xiàn)),根據(jù)事件循環(huán)機(jī)制,先入隊(duì)列的先執(zhí)行,所以如果我們?cè)趎extTick當(dāng)中執(zhí)行操作就會(huì)變成這樣。


2、 使用setTimeout來(lái)延遲執(zhí)行show方法,原理同上

所以我們的解決方法可以是:

this.name = data.name
setTimeout(() => {
 this.$refs.pop.show()
})

或者

this.name = data.name
this.$nextTick(() => {
 this.$refs.pop.show()
})

nextTick的實(shí)現(xiàn)原理

其實(shí)nextTick的實(shí)現(xiàn)原理是挺簡(jiǎn)單的,簡(jiǎn)單點(diǎn)說(shuō),就是實(shí)現(xiàn)異步,通過(guò)不同的執(zhí)行環(huán)境,用不同的方式來(lái)實(shí)現(xiàn),保證nextTick里面的回調(diào)函數(shù)能夠異步執(zhí)行。為什么要這么做呢?因?yàn)関ue對(duì)dom的更新也是異步的呀。

下面貼出源碼:

/**
 * Defer a task to execute it asynchronously.
 */
export const nextTick = (function () {
 const callbacks = []
 let pending = false
 let timerFunc

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

 // 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 if */
 if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError)
   // 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)
  }
 } else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  // PhantomJS and iOS 7.x
  MutationObserver.toString() === '[object MutationObserverConstructor]'
 )) {
  // use MutationObserver where native Promise is not available,
  // e.g. PhantomJS, iOS7, Android 4.4
  var counter = 1
  var observer = new MutationObserver(nextTickHandler)
  var textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
   textNode.data = String(counter)
  }
 } else {
  // fallback to setTimeout
  /* istanbul ignore next */
  timerFunc = () => {
   setTimeout(nextTickHandler, 0)
  }
 }

 return function queueNextTick (cb?: Function, ctx?: Object) {
  let _resolve
  callbacks.push(() => {
   if (cb) {
    try {
     cb.call(ctx)
    } catch (e) {
     handleError(e, ctx, 'nextTick')
    }
   } else if (_resolve) {
    _resolve(ctx)
   }
  })
  if (!pending) {
   pending = true
   timerFunc()
  }
  if (!cb && typeof Promise !== 'undefined') {
   return new Promise((resolve, reject) => {
    _resolve = resolve
   })
  }
 }
})()

首先我們看到這個(gè)是利用了閉包的特性,返回queueNextTick,所以我們實(shí)際調(diào)用的nextTick其實(shí)就是調(diào)用queueNextTick,一調(diào)用這個(gè)方法,就會(huì)把nextTick的回調(diào)放入隊(duì)列callbacks當(dāng)中,等到合適的時(shí)機(jī),會(huì)將callbacks中的所有回調(diào)取出來(lái)執(zhí)行,以達(dá)到延遲執(zhí)行的目的。為啥要用閉包呢,我覺(jué)得有兩個(gè)原因:

1、共享變量,比如callbacks、pending和timerFunc。

2、避免反復(fù)判斷,即是避免反復(fù)判斷timerFunc是利用Promise還是利用MutationObserver或是setTimeout來(lái)實(shí)現(xiàn)異步,這是函數(shù)柯里化的一種運(yùn)用。

這里有兩個(gè)最主要的方法需要解釋下:

1、 nextTickHandler

這個(gè)函數(shù),就是把隊(duì)列中的回調(diào),全部取出來(lái)執(zhí)行,類似于microtask的任務(wù)隊(duì)列。我們通過(guò)調(diào)用Vue.$nextTick就會(huì)把回調(diào)全部放入這個(gè)隊(duì)列當(dāng)中,等到要執(zhí)行的時(shí)候,調(diào)用nextTickHandler全部取出來(lái)執(zhí)行。

2、 timerFunc

這個(gè)變量,它的作用就是通過(guò)Promise/Mutationobserver/Settimeout把nextTickHandler放入到真正的任務(wù)隊(duì)列當(dāng)中,等到事件循環(huán)結(jié)束,就從任務(wù)隊(duì)列當(dāng)中取出nextTickHandler來(lái)執(zhí)行,nextTickHandler一執(zhí)行,callbacks里面的所有回調(diào)就會(huì)被取出來(lái)執(zhí)行來(lái),這樣就達(dá)到來(lái)延遲執(zhí)行nextTick傳的回調(diào)的效果。

通過(guò)這個(gè)簡(jiǎn)單的源碼分析,我們可以得出兩個(gè)結(jié)論

1、nextTick會(huì)根據(jù)不同的執(zhí)行環(huán)境,異步任務(wù)可能為microtask或者macrotask,而不是固定不變的。所以,如果你想讓nextTick里面的異步任務(wù)統(tǒng)統(tǒng)看成是microtask的話,你會(huì)遇到坑的。

2、nextTick的并不能保證一定能獲取得到更新后的dom,這取決于你是先進(jìn)行數(shù)據(jù)賦值還是先調(diào)用nextTick。比如:

new Vue({
   el: '#app',
   data() {
    return {
     id: 2
    }
   },
   created() {
    
   },
   mounted() {
    this.$nextTick(() => {
     console.log(document.getElementById('id').textContent) // 這里打印出來(lái)的是2,因?yàn)橄日{(diào)用了nextTick
    })
    this.id = 3
   }
 })

結(jié)論

如果想要獲取更新后的DOM或者子組件(依賴父組件的傳值),可以在更新操作之后立即使用Vue.nextTick(callback),注意這里的先后順序,先進(jìn)行更新操作,再調(diào)用nextTick獲取更新后的DOM/子組件,源碼里面我們知道nextTick是無(wú)法保證一定是能夠獲取得到更新后的DOM/子組件的

以上所述是小編給大家介紹的vue中的nextTick的使用,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • vue跨域proxy代理配置詳解

    vue跨域proxy代理配置詳解

    今天被vue中proxy配置困擾了一天,記錄一下,下面這篇文章主要給大家介紹了關(guān)于Vue配置文件中的proxy配置方式的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • vue.js選中動(dòng)態(tài)綁定的radio的指定項(xiàng)

    vue.js選中動(dòng)態(tài)綁定的radio的指定項(xiàng)

    這篇文章主要介紹了vue.js選中動(dòng)態(tài)綁定的radio的指定項(xiàng),需要的朋友可以參考下
    2017-06-06
  • vue 2.0封裝model組件的方法

    vue 2.0封裝model組件的方法

    本篇文章主要介紹了vue 2.0封裝model組件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • vue實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)按鈕

    vue實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)按鈕

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)按鈕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 解決echarts圖表使用v-show控制圖表顯示不全的問(wèn)題

    解決echarts圖表使用v-show控制圖表顯示不全的問(wèn)題

    這篇文章主要介紹了解決echarts圖表使用v-show控制圖表顯示不全的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • Vue.js組件tab實(shí)現(xiàn)選項(xiàng)卡切換

    Vue.js組件tab實(shí)現(xiàn)選項(xiàng)卡切換

    這篇文章主要為大家詳細(xì)介紹了Vue.js組件tab實(shí)現(xiàn)選項(xiàng)卡切換的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Vue.directive 自定義指令的問(wèn)題小結(jié)

    Vue.directive 自定義指令的問(wèn)題小結(jié)

    這篇文章主要介紹了Vue.directive 自定義指令的問(wèn)題小結(jié),需要的朋友可以參考下
    2018-03-03
  • vue transition組件及常用屬性

    vue transition組件及常用屬性

    在使用Vue過(guò)渡動(dòng)畫(huà)時(shí),注意選擇器優(yōu)先級(jí),謹(jǐn)慎合并樣式,Vue2中關(guān)于顯示隱藏的類名有v-enter、v-leave以及v-enter-active、v-leave-active等,這些可以用來(lái)定義動(dòng)畫(huà)的持續(xù)時(shí)間和樣式,感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • vue實(shí)現(xiàn)子路由調(diào)用父路由的方法

    vue實(shí)現(xiàn)子路由調(diào)用父路由的方法

    這篇文章主要介紹了vue實(shí)現(xiàn)子路由調(diào)用父路由的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Vue項(xiàng)目服務(wù)器部署之子目錄部署方法

    Vue項(xiàng)目服務(wù)器部署之子目錄部署方法

    在本文中我們給大家整理了關(guān)于Vue項(xiàng)目服務(wù)器部署之子目錄部署方法和具體步驟,需要的朋友們參考下。
    2019-05-05

最新評(píng)論