最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Vue.nextTick 的實(shí)現(xiàn)方法

 更新時(shí)間:2017年10月25日 09:35:55   作者:jirengu_楊然  
本篇文章主要介紹了Vue.nextTick 的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

這是一篇繼event loop和MicroTask 后的vue.nextTick API實(shí)現(xiàn)的源碼解析。

預(yù)熱,寫一個(gè)sleep函數(shù)

function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms)
}
async function oneTick (ms) {
 console.log('start')
 await sleep(ms)
 console.log('end')
}
oneTick(3000)

解釋下sleep函數(shù)

async 函數(shù)進(jìn)行await PromiseFn()時(shí)函數(shù)執(zhí)行是暫停的,我們也知道現(xiàn)在這個(gè)PromiseFn是在microTask內(nèi)執(zhí)行。當(dāng)microTask沒執(zhí)行完畢時(shí),后面的macroTask是不會(huì)執(zhí)行的,我們也就通過microTask在event loop的特性實(shí)現(xiàn)了一個(gè)sleep函數(shù),阻止了console.log的執(zhí)行

流程

1執(zhí)行console.log('start')
2執(zhí)行await 執(zhí)行暫停,等待await函數(shù)后的PromiseFn在microTask執(zhí)行完畢
3在sleep函數(shù)內(nèi),延遲ms返回
4返回resolve后執(zhí)行console.log('end')

nextTick API

vue中nextTick的使用方法

vue.nextTick(() => {
 // todo...
})

了解用法后看一下源碼

const nextTick = (function () {
 const callbacks = []
 let pending = false
 let timerFunc // 定時(shí)函數(shù)

 function nextTickHandler () {
  pending = false
  const copies = callbacks.slice(0) // 復(fù)制
  callbacks.length = 0 // 清空
  for (let i = 0; i < copies.length; i++) {
   copies[i]() // 逐個(gè)執(zhí)行
  }
 }

 if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError) // 重點(diǎn)
  }
 } else if ('!isIE MutationObserver') {
  var counter = 1
  var observer = new MutationObserver(nextTickHandler) // 重點(diǎn)
  var textNode = document.createTextNode(string(conter))

  observer.observe(textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
   textNode.data = String(counter)
  }
 } else {
  timerFunc = () => {
   setTimeout(nextTickHandler, 0) // 重點(diǎn)
  }
 }


 return function queueNextTick (cb, ctx) { // api的使用方式
  let _resolve
  callbacks.push(() => {
   if (cb) {
    try {
     cb.call(ctx)
    } catch (e) {
     err
    }
   } else if (_resolve) {
    _resolve(ctx)
   }
  })
  if (!pending) {
   pending = true
   timerFunc()
  }
  if (!cb && typeof Promise !== 'undefined') {
   return new Promise((resolve, reject) => {
    _resolve =resolve
   })
  }
 }
})() // 自執(zhí)行函數(shù)

大致看一下源碼可以了解到nextTick api是一個(gè)自執(zhí)行函數(shù)

既然是自執(zhí)行函數(shù),直接看它的return類型,return function queueNextTick (cb, ctx) {...}

return function queueNextTick (cb, ctx) { // api的使用方式
  let _resolve
  callbacks.push(() => {
   if (cb) {
    try {
     cb.call(ctx)
    } catch (e) {
     err
    }
   } else if (_resolve) {
    _resolve(ctx)
   }
  })
  if (!pending) {
   pending = true
   timerFunc()
  }
  if (!cb && typeof Promise !== 'undefined') {
   return new Promise((resolve, reject) => {
    _resolve =resolve
   })
  }
 }

只關(guān)注主流程queueNextTick函數(shù)把我們傳入的() => { // todo... } 推入了callbacks內(nèi)

 if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError) // 重點(diǎn)
  }
 } else if ('!isIE MutationObserver') {
  var counter = 1
  var observer = new MutationObserver(nextTickHandler) // 重點(diǎn)
  var textNode = document.createTextNode(string(conter))

  observer.observe(textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
   textNode.data = String(counter)
  }
 } else {
  timerFunc = () => {
   setTimeout(nextTickHandler, 0) // 重點(diǎn)
  }
 }

這一段我們可以看到標(biāo)注的三個(gè)點(diǎn)表明在不同瀏覽器環(huán)境下使用Promise, MutationObserver或setTimeout(fn, 0) 來執(zhí)行nextTickHandler

function nextTickHandler () {
  pending = false
  const copies = callbacks.slice(0) // 復(fù)制
  callbacks.length = 0 // 清空
  for (let i = 0; i < copies.length; i++) {
   copies[i]() // 逐個(gè)執(zhí)行
  }
 }

nextTickHandler就是把我們之前放入callbacks的 () => { // todo... } 在當(dāng)前tasks內(nèi)執(zhí)行。

寫一個(gè)簡(jiǎn)單的nextTick

源碼可能比較繞,我們自己寫一段簡(jiǎn)單的nextTick

const simpleNextTick = (function () {
 let callbacks = []
 let timerFunc

 return function queueNextTick (cb) {
  callbacks.push(() => { // 給callbacks 推入cb()
   cb()
  })

  timerFunc = () => {
   return Promise.resolve().then(() => {
    const fn = callbacks.shift()
    fn()
   })
  }
  timerFunc() // 執(zhí)行timerFunc,返回到是一個(gè)Promise
 }
})()

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

我們可以從這里看出nextTick的原理就是返回出一個(gè)Promise,而我們todo的代碼在這個(gè)Promise中執(zhí)行,現(xiàn)在我們還可以繼續(xù)簡(jiǎn)化

const simpleNextTick = (function () {
 return function queueNextTick (cb) {
  timerFunc = () => {
   return Promise.resolve().then(() => {
    cb()
   })
  }
  timerFunc()
 }
})()

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

直接寫成這樣。

const simpleNextTick = function queueNextTick (cb) {
  timerFunc = () => {
   return Promise.resolve().then(() => {
    cb()
   })
  }
  timerFunc()
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

這次我們把自執(zhí)行函數(shù)也簡(jiǎn)化掉

const simpleNextTick = function queueNextTick (cb) {
   return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick')
})

現(xiàn)在我們直接簡(jiǎn)化到最后,現(xiàn)在發(fā)現(xiàn)nextTick最核心的內(nèi)容就是Promise,一個(gè)microtask。

現(xiàn)在我們回到vue的nextTick API官方示例

<div id="example">{{message}}</div>
var vm = new Vue({
 el: '#example',
 data: {
  message: '123'
 }
})
vm.message = 'new message' // 更改數(shù)據(jù)
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
 vm.$el.textContent === 'new message' // true
})

原來在vue內(nèi)數(shù)據(jù)的更新后dom更新是要在下一個(gè)事件循環(huán)后執(zhí)行的。
nextTick的使用原則主要就是解決單一事件更新數(shù)據(jù)后立即操作dom的場(chǎng)景。

既然我們知道了nextTick核心是利用microTasks,那么我們把簡(jiǎn)化過的nextTick和開頭的sleep函數(shù)對(duì)照一下。

const simpleNextTick = function queueNextTick (cb) {
   return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, 'nextTick') // 也可以換成ajax請(qǐng)求
})
function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms) // 也可以換成ajax請(qǐng)求
}
async function oneTick (ms) {
 console.log('start')
 await sleep(ms)
 console.log('end')
}
oneTick(3000)

我們看出nextTick和我么寫的oneTick的執(zhí)行結(jié)果是那么的相似。區(qū)別只在于nextTick是把callback包裹一個(gè)Promise返回并執(zhí)行,而oneTick是用await執(zhí)行一個(gè)Promise函數(shù),而這個(gè)Promise有自己包裹的webapi函數(shù)。

那在用ajax請(qǐng)求的時(shí)候我們是不是直接這樣使用axios可以返回Promise的庫(kù)

async function getData () {
  const data = await axios.get(url)
  // 操作data的數(shù)據(jù)來改變dom
  return data
}

這樣也可以達(dá)到同nextTick同樣的作用

最后我們也可以從源碼中看出,當(dāng)瀏覽器環(huán)境不支持Promise時(shí)可以使用MutationObserver或setTimeout(cb, 0) 來達(dá)到同樣的效果。但最終的核心是microTask

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Vue如何使用本地JSON文件

    Vue如何使用本地JSON文件

    這篇文章主要介紹了Vue如何使用本地JSON文件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Vue事件總線怎么用

    Vue事件總線怎么用

    這篇文章主要介紹了Vue事件總線的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • vue項(xiàng)目完成后如何實(shí)現(xiàn)項(xiàng)目?jī)?yōu)化的示例

    vue項(xiàng)目完成后如何實(shí)現(xiàn)項(xiàng)目?jī)?yōu)化的示例

    本文主要介紹了vue項(xiàng)目完成后如何實(shí)現(xiàn)項(xiàng)目?jī)?yōu)化的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Vue前端如何設(shè)置Cookie和鑒權(quán)問題詳解

    Vue前端如何設(shè)置Cookie和鑒權(quán)問題詳解

    這篇文章主要介紹了前端如何設(shè)置和使用Cookie,并對(duì)比了Cookie和Token在鑒權(quán)中的優(yōu)缺點(diǎn),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-02-02
  • 詳解vue.js+UEditor集成 [前后端分離項(xiàng)目]

    詳解vue.js+UEditor集成 [前后端分離項(xiàng)目]

    本篇文章主要介紹了詳解vue.js+UEditor集成 [前后端分離項(xiàng)目] ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Vue Router history模式的配置方法及其原理

    Vue Router history模式的配置方法及其原理

    這篇文章主要介紹了Vue Router history模式的配置方法及其原理,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05
  • Vue自定義全局彈窗組件操作

    Vue自定義全局彈窗組件操作

    這篇文章主要介紹了Vue自定義全局彈窗組件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Vue項(xiàng)目?jī)?yōu)化打包詳解

    Vue項(xiàng)目?jī)?yōu)化打包詳解

    這篇文章主要為大家介紹了Vue項(xiàng)目的優(yōu)化打包,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • 解決element ui select下拉框不回顯數(shù)據(jù)問題的解決

    解決element ui select下拉框不回顯數(shù)據(jù)問題的解決

    這篇文章主要介紹了解決element ui select下拉框不回顯數(shù)據(jù)問題的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Vue開發(fā)之watch監(jiān)聽數(shù)組、對(duì)象、變量操作分析

    Vue開發(fā)之watch監(jiān)聽數(shù)組、對(duì)象、變量操作分析

    這篇文章主要介紹了Vue開發(fā)之watch監(jiān)聽數(shù)組、對(duì)象、變量操作,結(jié)合實(shí)例形式分析了vue.js使用Watch針對(duì)數(shù)組、對(duì)象、變量監(jiān)聽相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04

最新評(píng)論

左贡县| 大荔县| 黄山市| 密云县| 临颍县| 方城县| 色达县| 吉木萨尔县| 平果县| 夏邑县| 遂昌县| 寿宁县| 渑池县| 太保市| 镇平县| 剑川县| 邓州市| 平定县| 禄劝| 武宣县| 屏南县| 嘉峪关市| 湘乡市| 铜山县| 乌兰浩特市| 凤凰县| 武强县| 扶沟县| 云阳县| 宜城市| 奇台县| 沭阳县| 建始县| 宕昌县| 吴桥县| 客服| 休宁县| 巴林右旗| 永登县| 应城市| 阿合奇县|