国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Vue源碼中的nextTick的實現邏輯

Anshiii / 1631人閱讀

摘要:這是因為在運行時出錯,我們不這個錯誤的話,會導致整個程序崩潰掉。如果沒有向中傳入,并且瀏覽器支持的話,我們的返回的將是一個。如果不支持,就降低到用,整體邏輯就是這樣。。

我們知道vue中有一個api。Vue.nextTick( [callback, context] )
他的作用是在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。那么這個api是怎么實現的呢?你肯定也有些疑問或者好奇。下面就是我的探索,分享給大家,也歡迎大家到github上和我進行討論哈~~

首先貼一下vue的源碼,然后我們再一步步的分析

/* @flow */
/* globals MessageChannel */

import { noop } from "shared/util"
import { handleError } from "./error"
import { isIOS, isNative } from "./env"

const callbacks = []
let pending = false

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

// Here we have async deferring wrappers using both microtasks and (macro) tasks.
// In < 2.4 we used microtasks everywhere, but there are some scenarios where
// microtasks have too high a priority and fire in between supposedly
// sequential events (e.g. #4521, #6690) or even between bubbling of the same
// event (#6566). However, using (macro) tasks everywhere also has subtle problems
// when state is changed right before repaint (e.g. #6813, out-in transitions).
// Here we use microtask by default, but expose a way to force (macro) task when
// needed (e.g. in event handlers attached by v-on).
let microTimerFunc
let macroTimerFunc
let useMacroTask = false

// Determine (macro) task defer implementation.
// Technically setImmediate should be the ideal choice, but it"s only available
// in IE. The only polyfill that consistently queues the callback after all DOM
// events triggered in the same loop is by using MessageChannel.
/* istanbul ignore if */
if (typeof setImmediate !== "undefined" && isNative(setImmediate)) {
  macroTimerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else if (typeof MessageChannel !== "undefined" && (
  isNative(MessageChannel) ||
  // PhantomJS
  MessageChannel.toString() === "[object MessageChannelConstructor]"
)) {
  const channel = new MessageChannel()
  const port = channel.port2
  channel.port1.onmessage = flushCallbacks
  macroTimerFunc = () => {
    port.postMessage(1)
  }
} else {
  /* istanbul ignore next */
  macroTimerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

// Determine microtask defer implementation.
/* istanbul ignore next, $flow-disable-line */
if (typeof Promise !== "undefined" && isNative(Promise)) {
  const p = Promise.resolve()
  microTimerFunc = () => {
    p.then(flushCallbacks)
    // 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 {
  // fallback to macro
  microTimerFunc = macroTimerFunc
}

/**
 * Wrap a function so that if any code inside triggers state change,
 * the changes are queued using a (macro) task instead of a microtask.
 */
export function withMacroTask (fn: Function): Function {
  return fn._withTask || (fn._withTask = function () {
    useMacroTask = true
    const res = fn.apply(null, arguments)
    useMacroTask = false
    return res
  })
}

export function nextTick (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
    if (useMacroTask) {
      macroTimerFunc()
    } else {
      microTimerFunc()
    }
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== "undefined") {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

這么多代碼,可能猛的一看,可能有點懵,不要緊,我們一步一步抽出枝干。首先我們看一下這個js文件里的nextTick的定義

export function nextTick (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
    if (useMacroTask) {
      macroTimerFunc()
    } else {
      microTimerFunc()
    }
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== "undefined") {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

我將代碼精簡一下。如下所示,下面的代碼估計就比較容易看懂了。把cb函數放到會掉隊列里去,如果支持macroTask,則利用macroTask在下一個事件循環中執行這些異步的任務,如果不支持macroTask,那就利用microTask在下一個事件循環中執行這些異步任務。

export function nextTick (cb?: Function, ctx?: Object) {
  callbacks.push(cb)
    if (useMacroTask) {
      macroTimerFunc()
    } else {
      microTimerFunc()
    }
}

這里再次普及一下js的event loop的相關知識,js中的兩個任務隊列 :macrotasks、microtasks

macrotasks: script(一個js文件),setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks: process.nextTick, Promises, Object.observe, MutationObserver

執行過程:
1.js引擎從macrotask隊列中取一個任務執行
2.然后將microtask隊列中的所有任務依次執行完
3.再次從macrotask隊列中取一個任務執行
4.然后再次將microtask隊列中所有任務依次執行完
……
循環往復

那么我們再看我們精簡掉的代碼都是干什么的呢?我們往異步隊列里放回調函數的時候,我們并不是直接放回調函數,而是包裝了一個函數,在這個函數里調用cb,并且用try catch包裹了一下。這是因為cb在運行時出錯,我們不try catch這個錯誤的話,會導致整個程序崩潰掉。 我們還精簡掉了如下代碼

  if (!cb && typeof Promise !== "undefined") {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }

這段代碼是干嘛的呢?也就是說我們用nextTick的時候,還可以有promise的寫法。如果沒有向nextTick中傳入cb,并且瀏覽器支持Promise的話,我們的nextTick返回的將是一個Promise。所以,nextTick的寫法也可以是如下這樣的

 nextTick().then(()=>{console.log("XXXXX")})

vue源碼里關于nextTick的封裝的思路,也給我們一些非常有益的啟示,就是我們平時在封裝函數的時候,要想同時指出回調和promise的話,就可以借鑒vue中的思路。

大致的思路我們已經捋順了。但是為什么執行macroTimerFunc或者microTimerFunc就會在下一個tick執行我們的回調隊列呢?下面我們來分析一下這兩個函數的定義。首先我們分析macroTimerFunc

let macroTimerFunc

if (typeof setImmediate !== "undefined" && isNative(setImmediate)) {
  macroTimerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else if (typeof MessageChannel !== "undefined" && (
  isNative(MessageChannel) ||
  // PhantomJS
  MessageChannel.toString() === "[object MessageChannelConstructor]"
)) {
  const channel = new MessageChannel()
  const port = channel.port2
  channel.port1.onmessage = flushCallbacks
  macroTimerFunc = () => {
    port.postMessage(1)
  }
} else {
  /* istanbul ignore next */
  macroTimerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

從上邊的代碼可以看出,如果瀏覽器支持setImmediate,我們就用setImmediate,如果瀏覽器支持MessageChannel,我們就用MessageChannel的異步特性,如果兩者都不支持,我們就降價到setTimeout
,用setTimeout來把callbacks中的任務在下一個tick中執行

  macroTimerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }

分析完macroTimerFunc,下面我們開始分析microTimerFunc,我把vue源碼中關于microTimerFunc的定義稍微精簡一下

let microTimerFunc;
if (typeof Promise !== "undefined" && isNative(Promise)) {
  const p = Promise.resolve()
  microTimerFunc = () => {
    p.then(flushCallbacks)
  }
} else {
  // fallback to macro
  microTimerFunc = macroTimerFunc
}

從上邊精簡之后的代碼,我們可以看到microTimerFunc的實現思路。如果支持瀏覽器支持promise,就用promise實現。如果不支持,就降低到用macroTimerFunc

over,整體邏輯就是這樣。。看著嚇人,掰開了之后好好分析一下,還是挺簡單的。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/96240.html

相關文章

  • 詳細分析Vue.nextTick()實現

    摘要:因為平時使用都是傳回調的,所以很好奇什么情況下會為,去翻看官方文檔發現起新增如果沒有提供回調且在支持的環境中,則返回一個。這就對了,函數體內最后的判斷很明顯就是這個意思沒有回調支持。 Firstly, this paper is based on Vue 2.6.8剛開始接觸Vue的時候,哇nextTick好強,咋就在這里面寫就是dom更新之后,當時連什么macrotask、micro...

    DevYK 評論0 收藏0
  • 你不知道$nextTick

    摘要:復制代碼然后在這個文件里還有一個函數叫用來把保存的回調函數給全執行并清空。其實調用的不僅是開發者,更新時,也用到了。但是問題又來了,根據瀏覽器的渲染機制,渲染線程是在微任務執行完成之后運行的。 當在代碼中更新了數據,并希望等到對應的Dom更新之后,再執行一些邏輯。這時,我們就會用到$nextTickfuncion call...

    番茄西紅柿 評論0 收藏2637
  • Vue源碼詳解之nextTick:MutationObserver只是浮云,microtask才是核

    摘要:后來尤雨溪了解到是將回調放入的隊列。而且瀏覽器內部為了更快的響應用戶,內部可能是有多個的而的的優先級可能更高,因此對于尤雨溪采用的,甚至可能已經多次執行了的,都沒有執行的,也就導致了我們更新操 原發于我的博客。 前一篇文章已經詳細記述了Vue的核心執行過程。相當于已經搞定了主線劇情。后續的文章都會對其中沒有介紹的細節進行展開。 現在我們就來講講其他支線任務:nextTick和micro...

    陳偉 評論0 收藏0
  • VueJS源碼學習——元素在插入和移出 dom 時過渡邏輯

    摘要:原文地址項目地址關于中使用效果,官網上的解釋如下當元素插入到樹或者從樹中移除的時候,屬性提供變換的效果,可以使用來定義變化效果,也可以使用來定義首先第一個函數是將元素插入,函數實現調用了實現代碼如下寫的好的代碼就是文檔,從注釋和命名上就 src/transition 原文地址項目地址 關于 vue 中使用 transition 效果,官網上的解釋如下: With Vue.js’ tra...

    Dogee 評論0 收藏0
  • Vue原理】NextTick - 源碼版 之 獨立自身

    摘要:盡量把所有異步代碼放在一個宏微任務中,減少消耗加快異步代碼的執行。我們知道,如果一個異步代碼就注冊一個宏微任務的話,那么執行完全部異步代碼肯定慢很多避免頻繁地更新。中就算我們一次性修改多次數據,頁面還是只會更新一次。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5...

    劉東 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<