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

資訊專欄INFORMATION COLUMN

Vue源碼中的nextTick的實(shí)現(xiàn)邏輯

Anshiii / 1620人閱讀

摘要:這是因?yàn)樵谶\(yùn)行時(shí)出錯(cuò),我們不這個(gè)錯(cuò)誤的話,會(huì)導(dǎo)致整個(gè)程序崩潰掉。如果沒有向中傳入,并且瀏覽器支持的話,我們的返回的將是一個(gè)。如果不支持,就降低到用,整體邏輯就是這樣。。

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

首先貼一下vue的源碼,然后我們?cè)僖徊讲降姆治?/p>

/* @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
    })
  }
}

這么多代碼,可能猛的一看,可能有點(diǎn)懵,不要緊,我們一步一步抽出枝干。首先我們看一下這個(gè)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
    })
  }
}

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

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

這里再次普及一下js的event loop的相關(guān)知識(shí),js中的兩個(gè)任務(wù)隊(duì)列 :macrotasks、microtasks

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

執(zhí)行過程:
1.js引擎從macrotask隊(duì)列中取一個(gè)任務(wù)執(zhí)行
2.然后將microtask隊(duì)列中的所有任務(wù)依次執(zhí)行完
3.再次從macrotask隊(duì)列中取一個(gè)任務(wù)執(zhí)行
4.然后再次將microtask隊(duì)列中所有任務(wù)依次執(zhí)行完
……
循環(huán)往復(fù)

那么我們?cè)倏次覀兙喌舻拇a都是干什么的呢?我們往異步隊(duì)列里放回調(diào)函數(shù)的時(shí)候,我們并不是直接放回調(diào)函數(shù),而是包裝了一個(gè)函數(shù),在這個(gè)函數(shù)里調(diào)用cb,并且用try catch包裹了一下。這是因?yàn)閏b在運(yùn)行時(shí)出錯(cuò),我們不try catch這個(gè)錯(cuò)誤的話,會(huì)導(dǎo)致整個(gè)程序崩潰掉。 我們還精簡掉了如下代碼

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

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

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

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

大致的思路我們已經(jīng)捋順了。但是為什么執(zhí)行macroTimerFunc或者microTimerFunc就會(huì)在下一個(gè)tick執(zhí)行我們的回調(diào)隊(duì)列呢?下面我們來分析一下這兩個(gè)函數(shù)的定義。首先我們分析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的異步特性,如果兩者都不支持,我們就降價(jià)到setTimeout
,用setTimeout來把callbacks中的任務(wù)在下一個(gè)tick中執(zhí)行

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

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

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

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

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

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/96240.html

相關(guān)文章

  • 詳細(xì)分析Vue.nextTick()實(shí)現(xiàn)

    摘要:因?yàn)槠綍r(shí)使用都是傳回調(diào)的,所以很好奇什么情況下會(huì)為,去翻看官方文檔發(fā)現(xiàn)起新增如果沒有提供回調(diào)且在支持的環(huán)境中,則返回一個(gè)。這就對(duì)了,函數(shù)體內(nèi)最后的判斷很明顯就是這個(gè)意思沒有回調(diào)支持。 Firstly, this paper is based on Vue 2.6.8剛開始接觸Vue的時(shí)候,哇nextTick好強(qiáng),咋就在這里面寫就是dom更新之后,當(dāng)時(shí)連什么macrotask、micro...

    DevYK 評(píng)論0 收藏0
  • 你不知道$nextTick

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

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

    摘要:后來尤雨溪了解到是將回調(diào)放入的隊(duì)列。而且瀏覽器內(nèi)部為了更快的響應(yīng)用戶,內(nèi)部可能是有多個(gè)的而的的優(yōu)先級(jí)可能更高,因此對(duì)于尤雨溪采用的,甚至可能已經(jīng)多次執(zhí)行了的,都沒有執(zhí)行的,也就導(dǎo)致了我們更新操 原發(fā)于我的博客。 前一篇文章已經(jīng)詳細(xì)記述了Vue的核心執(zhí)行過程。相當(dāng)于已經(jīng)搞定了主線劇情。后續(xù)的文章都會(huì)對(duì)其中沒有介紹的細(xì)節(jié)進(jìn)行展開。 現(xiàn)在我們就來講講其他支線任務(wù):nextTick和micro...

    陳偉 評(píng)論0 收藏0
  • VueJS源碼學(xué)習(xí)——元素在插入和移出 dom 時(shí)過渡邏輯

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

    Dogee 評(píng)論0 收藏0
  • Vue原理】NextTick - 源碼版 之 獨(dú)立自身

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

    劉東 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<