亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

Vue中之nextTick函數源碼分析詳解

2019-11-19 15:09:43
字體:
來源:轉載
供稿:網友

1. 什么是Vue.nextTick()?

官方文檔解釋如下:

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

2. 為什么要使用nextTick?

<!DOCTYPE html><html> <head> <title>演示Vue</title> <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"></script> </head> <body> <div id="app">  <template>  <div ref="list">   {{name}}  </div>  </template> </div> <script>  new Vue({  el: '#app',  data: {   name: 'aa'  },  mounted() {   this.updateData();  },  methods: {   updateData() {   var self = this;   this.name = 'bb';   console.log(this.$el.textContent); // aa   this.$nextTick(function(){    console.log(self.$el.textContent); // bb   });   }  }  }); </script> </body></html>

如上代碼 在頁面視圖上顯示bb,但是當我在控制臺打印的時候,獲取的文本內容還是 aa,但是使用 nextTick后,獲取的文本內容就是最新的內容bb了,因此在這種情況下,我們可以使用nextTick函數了。

上面的代碼為什么改變this.name = 'bb';后,再使用console.log(this.$el.textContent);打印的值還是aa呢?那是因為設置name的值后,DOM還沒有更新到,所以獲取值還是之前的值,但是我們放到nextTick函數里面的時候,代碼會在DOM更新后執行,因此DOM更新后,再去獲取元素的值就可以獲取到最新值了。

理解DOM更新:在VUE中,當我們修改了data中的某一個值后,并不會立即反應到該el中,vue將對更改的數據放到watcher的一個異步隊列中,只有在當前任務空閑時才會執行watcher隊列任務,這就有一個延遲時間,因此放到 nextTick函數后就可以獲取該el的最新值了。如果我們把上面的nextTick改成setTimeout也是可以的。

3. Vue源碼詳解之nextTick(源碼在 vue/src/core/util/env.js)

在理解nextTick源碼之前,我們先來理解下 html5中新增的 MutationObserver的API,它的作用是用來監聽DOM變動的接口,它能監聽一個dom對象發生的子節點刪除,屬性修改,文本內容修改等等。

nextTick源碼如下:

export const nextTick = (function () { const callbacks = [] let pending = false let timerFunc function nextTickHandler () { pending = false; /*  之所以要slice復制一份出來是因為有的cb執行過程中又會往callbacks中加入內容,比如$nextTick的回調函數里又有$nextTick,  那么這些應該放入到下一個輪次的nextTick去執行,所以拷貝一份,遍歷完成即可,防止一直循環下去。  */ 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 */ /* nextTick行為利用了microtask隊列, 先使用 Promise.resolve().then(nextTickHandler)來將異步回調 放入到microtask中,Promise 和 MutationObserver都可以使用,但是 MutationObserver 在IOS9.3以上的 WebView中有bug,因此如果滿足第一項的話就可以執行,如果沒有原生Promise就用 MutationObserver。 */ 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 (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 IE11, iOS7, Android 4.4 /*  創建一個MutationObserver,observe監聽到DOM改動之后執行的回調 nextTickHandler   */ var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)); // 使用MutationObserver的接口,監聽文本節點的字符內容 observer.observe(textNode, {  characterData: true }); /*  每次執行timerFunc函數都會讓文本節點的內容在0/1之間切換,切換之后將新賦值到那個我們MutationObserver監聽的文本節點上去。  */ timerFunc = () => {  counter = (counter + 1) % 2  textNode.data = String(counter) } } else { // fallback to setTimeout /*  如果上面的兩種都不支持的話,我們就使用setTimeout來執行  */ 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)  } }); /* 如果pending為true,表明本輪事件循環中已經執行過 timerFunc(nextTickHandler, 0) */ if (!pending) {  pending = true  timerFunc() } if (!cb && typeof Promise !== 'undefined') {  return new Promise((resolve, reject) => {  _resolve = resolve  }) } }})()

整體思路理解:首先 nextTick 是一個閉包函數,代碼立即執行,在理解整體代碼之前,我們先來看個類似的demo,如下代碼:

<!DOCTYPE html><html> <head> <title>演示Vue</title> </head> <body> <div id="app">   </div> <script>  var nextTick = (function(){  return function queueNextTick(cb, ctx) {   if (cb) {   try {    cb.call(ctx)   } catch (e) {    console.log('出錯了');   }   }  }  })();  // 方法調用  nextTick(function(){  console.log(2); // 打印2  }) </script> </body></html>

demo代碼和上面的代碼很類似。

我們也可以再來抽離使用nextTick做demo代碼如下:

var nextTick2 = (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]() } } if (typeof Promise !== 'undefined') { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => {  p.then(nextTickHandler).catch(logError) } } else if (typeof MutationObserver !== 'undefined' || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' ) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS IE11, 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, ctx) { 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  }) } }})();nextTick2(function(){ console.log(2222);});

如上代碼是nextTick源碼的抽離,為了更好的理解nextTick,做了如上的demo。

我們再來理解一下整體的代碼的含義;

先定義數組 callbacks = [];來存放所有需要執行的回調函數,定義let pending = false;判斷本輪事件是否執行過 timerFunc(nextTickHandler, 0)這個函數,為true說明執行過 timeFunc函數,接著定義nextTickHandler函數,該函數的作用是依次遍歷數組callbacks保存的函數,依次執行;

請看源代碼如下:

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

然后就是三個判斷了,代碼如下:

if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError);} else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]')){ 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 { timerFunc = () => { setTimeout(nextTickHandler, 0) }}

首先判斷是否支持Promise對象,如果支持的話,定義了timeFunc()函數,為了下一步調用做準備,然后繼續判斷是否支持該對象 MutationObserver,如果支持的話,創建一個文本節點,監聽該節點數據是否發生改變,如果發生改變的話,調用timerFunc函數,counter值會在0/1切換,如果值改變了的話,把該數據值賦值到data屬性上面去,那么data屬性發生改變了,就會重新渲染頁面(因為vue是通過Object.defineProperty來監聽屬性值是否發生改變),如果上面兩種情況都不滿足的話,那么直接使用setTimeout來執行nextTickHandler函數了;

最后nextTick代碼返回一個函數,代碼如下:

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 }) }}

代碼的含義是:傳入的cb是否是函數,ctx參數是否是一個對象,如果cb是一個函數的話,使用cb.call(ctx), 如果timerFunc沒有執行過的話,那么pending為false,因此執行 timerFunc()函數?;镜乃悸肪褪沁@樣的。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久不射热爱视频精品| 欧美最顶级丰满的aⅴ艳星| 中文字幕一精品亚洲无线一区| 亚洲国产精品久久久久秋霞不卡| 久久久这里只有精品视频| 国产91网红主播在线观看| 91精品国产色综合久久不卡98口| 青草成人免费视频| 国产区精品视频| 中文字幕免费精品一区高清| 国产91免费看片| 午夜精品福利在线观看| 88国产精品欧美一区二区三区| 欧美在线视频在线播放完整版免费观看| 8090成年在线看片午夜| 91中文精品字幕在线视频| 精品国产31久久久久久| 国产在线播放91| 亚洲精品免费在线视频| 日韩免费观看在线观看| 国产欧亚日韩视频| 中文字幕精品国产| 97超碰国产精品女人人人爽| 久久成人在线视频| 蜜臀久久99精品久久久久久宅男| 亚洲aⅴ日韩av电影在线观看| 久久伊人精品一区二区三区| 国产成人精品免高潮费视频| 欧美亚洲激情视频| 成人欧美一区二区三区在线湿哒哒| 精品久久久久久久久久久久久| 国产91ⅴ在线精品免费观看| 亚洲精品福利在线| 亚洲自拍高清视频网站| 91深夜福利视频| 91在线观看免费网站| 日韩欧美亚洲综合| 久久久免费高清电视剧观看| 一区二区三区回区在观看免费视频| 日韩欧美极品在线观看| 精品免费在线视频| 国产成人精品999| 久久亚洲精品网站| 国产久一一精品| 日韩a**中文字幕| 久久成人这里只有精品| 午夜精品一区二区三区在线播放| 欧美成人剧情片在线观看| 国产精品国产三级国产专播精品人| 欧洲成人免费aa| 91精品久久久久久久| 久久久久久久久久久亚洲| 久久激情视频久久| 欧美特级www| 亚洲综合在线中文字幕| 深夜福利91大全| 欧美高清videos高潮hd| 最近中文字幕日韩精品| 中文字幕一区电影| 欧洲日韩成人av| 日韩综合中文字幕| 欧美性受xxx| 亚洲欧洲一区二区三区在线观看| 日韩av在线电影网| 中文字幕日韩欧美在线| 亚洲人午夜色婷婷| 日韩中文视频免费在线观看| 伊人青青综合网站| 亚洲国产精久久久久久久| 国产精品你懂得| 欧美日韩在线观看视频小说| 国产成人精品久久二区二区| 亚洲美女精品久久| 久久99热精品这里久久精品| 欧洲日本亚洲国产区| 91高清视频免费观看| 性金发美女69hd大尺寸| 国产精品都在这里| 欧美日韩aaaa| 啊v视频在线一区二区三区| 久久影院资源站| 欧美日本精品在线| 成人激情春色网| 精品偷拍一区二区三区在线看| 九九热最新视频//这里只有精品| 综合久久五月天| 日韩网站免费观看| 国产一区香蕉久久| 欧美日韩国产中字| 日韩中文字幕在线看| 欧美一级高清免费播放| 国产精品久在线观看| 日韩第一页在线| 日韩在线观看免费高清完整版| 中日韩美女免费视频网站在线观看| 日韩中文字幕网站| 91视频免费网站| 亚洲最大福利视频网| 国内精品久久影院| 欧美限制级电影在线观看| 欧美激情欧美狂野欧美精品| 欧美日韩裸体免费视频| 亚洲午夜精品久久久久久久久久久久| 丁香五六月婷婷久久激情| 亚洲成人精品av| 亚洲国产精品大全| 这里只有精品丝袜| 国产亚洲欧美日韩一区二区| 91亚洲午夜在线| 国产视频精品va久久久久久| 国产亚洲在线播放| 国产成人短视频| 亚洲视频在线看| 欧美洲成人男女午夜视频| 欧美丰满少妇xxxxx做受| 欧美日韩国产精品一区| 日本中文字幕久久看| 最好看的2019年中文视频| 亚洲欧美国产日韩天堂区| 国产精品免费看久久久香蕉| 国产视频福利一区| 久久久精品国产| 国产欧美日韩专区发布| www.亚洲成人| 久久大大胆人体| 国产精品久久久久久久久免费看| 91极品女神在线| 国产精品丝袜久久久久久高清| 久久九九亚洲综合| 俺去啦;欧美日韩| 九九精品视频在线观看| 国产精品视频导航| 91精品久久久久久久久久久| 亚洲毛片在线看| 国产午夜精品一区二区三区| 久久久这里只有精品视频| 国产伦精品一区二区三区精品视频| 日韩av在线免费播放| 亚洲乱码一区av黑人高潮| 欧美黑人性猛交| 在线国产精品视频| 日韩免费在线电影| 97成人精品区在线播放| 日本高清+成人网在线观看| 国产精品偷伦免费视频观看的| www国产亚洲精品久久网站| 91老司机精品视频| 黑丝美女久久久| 姬川优奈aav一区二区| 欧美激情在线狂野欧美精品| 亚洲jizzjizz日本少妇| 国产精品嫩草视频| 国产日韩在线视频| 日本午夜精品理论片a级appf发布| 亚洲国产精品中文| 亚洲精品视频免费在线观看| 成人免费观看网址| 国产一区二区激情| 国产精品欧美日韩一区二区| 国产suv精品一区二区| 欧美亚洲另类视频| 亚洲综合日韩中文字幕v在线| 欧美精品性视频| 欧洲精品在线视频|