nextTicket源码构成

  • 1、能力检测
  • 2、延时调用
  • 3、原理是利用js同步函数执行完毕后才会执行进入异步加载流的规则

全部源码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* @flow */
/* globals MutationObserver */

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

export let isUsingMicroTask = false

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 microtasks.
//这里我们有使用微任务的异步延迟包装器。
// In 2.5 we used (macro) tasks (in combination with microtasks).
//在2.5中,我们使用(宏)任务(与微任务结合使用)。
// However, it has subtle problems when state is changed right before repaint
//然而,当状态在重新绘制之前发生变化时,就会出现一些微妙的问题
// (e.g. #6813, out-in transitions).
// Also, using (macro) tasks in event handler would cause some weird behaviors
//同样,在事件处理程序中使用(宏)任务会导致一些奇怪的行为
// that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109).
//这是无法回避的(例如#7109、#7153、#7546、#7834、#8109)。
// So we now use microtasks everywhere, again.
//所以 我们现在在任何地方都使用微任务
// A major drawback of this tradeoff is that there are some scenarios
//这种折中的情况会出现的主要问题就是存在一些场景
// where microtasks have too high a priority and fire in between supposedly
//这种情况下,微任务的优先级太高,而且介于两者之间
// sequential events (e.g. #4521, #6690, which have workarounds)
//顺序事件(例如#4521、#6690,它们有变通方法)
// or even between bubbling of the same event (#6566).
//甚至在冒泡同一个事件(#6566)之间。
let timerFunc

// The nextTick behavior leverages the microtask queue, which can be accessed
//nestTick 利用可以访问的微任务队列
// via either native Promise.then or MutationObserver.
//通过 Promise 或者 MutationObserver
// MutationObserver has wider support, however it is seriously bugged in
// MutationObserver有更广泛的支持,但是它被严重地窃听了
// 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:
// UIWebView 在 IOS >= 9.3.3中触发。当他被触发几次后会完全停止工作,所以,如果Promise可用,建议使用promise
/* istanbul ignore next, $flow-disable-line */
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    // In problematic UIWebViews, Promise.then doesn't completely break, but
    ////在有问题的uiwebview中,Promise。不会完全断裂,但是
    // 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)
  }
  isUsingMicroTask = true
} 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,
  //promise不可用的地方使用 MutationObserver
  // e.g. PhantomJS, iOS7, Android 4.4
  // (#6466 MutationObserver is unreliable in IE11)
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true

  // 优先检查是否支持setImmediate,这是一个高版本 IE 和 Edge 才支持的特性(和setTimeout差不多,但优先级最高)
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  // Fallback to setImmediate.
  // Techinically it leverages the (macro) task queue,
  //技术上它利用(宏)任务队列,
  // but it is still a better choice than setTimeout.
  //但他仍是比setTimeout更好的选择
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  // Fallback to setTimeout.
  // 回退到setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

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
    timerFunc()
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}