1
1
/* @flow */
2
-
/* globals MessageChannel */
2
+
/* globals MutationObserver */
3
3
4
4
import { noop } from 'shared/util'
5
5
import { handleError } from './error'
6
-
import { isIOS, isNative } from './env'
6
+
import { isIE, isIOS, isNative } from './env'
7
7
8
8
const callbacks = []
9
9
let pending = false
@@ -17,76 +17,67 @@ function flushCallbacks () {
17
17
}
18
18
}
19
19
20
-
// Here we have async deferring wrappers using both microtasks and (macro) tasks.
21
-
// In < 2.4 we used microtasks everywhere, but there are some scenarios where
22
-
// microtasks have too high a priority and fire in between supposedly
23
-
// sequential events (e.g. #4521, #6690) or even between bubbling of the same
24
-
// event (#6566). However, using (macro) tasks everywhere also has subtle problems
25
-
// when state is changed right before repaint (e.g. #6813, out-in transitions).
26
-
// Here we use microtask by default, but expose a way to force (macro) task when
27
-
// needed (e.g. in event handlers attached by v-on).
28
-
let microTimerFunc
29
-
let macroTimerFunc
30
-
let useMacroTask = false
20
+
// Here we have async deferring wrappers using microtasks.
21
+
// In 2.5 we used (macro) tasks (in combination with microtasks).
22
+
// However, it has subtle problems when state is changed right before repaint
23
+
// (e.g. #6813, out-in transitions).
24
+
// Also, using (macro) tasks in event handler would cause some weird behaviors
25
+
// that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109).
26
+
// So we now use microtasks everywhere, again.
27
+
// A major drawback of this tradeoff is that there are some scenarios
28
+
// where microtasks have too high a priority and fire in between supposedly
29
+
// sequential events (e.g. #4521, #6690, which have workarounds)
30
+
// or even between bubbling of the same event (#6566).
31
+
let timerFunc
31
32
32
-
// Determine (macro) task defer implementation.
33
-
// Technically setImmediate should be the ideal choice, but it's only available
34
-
// in IE. The only polyfill that consistently queues the callback after all DOM
35
-
// events triggered in the same loop is by using MessageChannel.
36
-
/* istanbul ignore if */
37
-
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
38
-
macroTimerFunc = () => {
39
-
setImmediate(flushCallbacks)
40
-
}
41
-
} else if (typeof MessageChannel !== 'undefined' && (
42
-
isNative(MessageChannel) ||
43
-
// PhantomJS
44
-
MessageChannel.toString() === '[object MessageChannelConstructor]'
45
-
)) {
46
-
const channel = new MessageChannel()
47
-
const port = channel.port2
48
-
channel.port1.onmessage = flushCallbacks
49
-
macroTimerFunc = () => {
50
-
port.postMessage(1)
51
-
}
52
-
} else {
53
-
/* istanbul ignore next */
54
-
macroTimerFunc = () => {
55
-
setTimeout(flushCallbacks, 0)
56
-
}
57
-
}
58
-
59
-
// Determine microtask defer implementation.
33
+
// The nextTick behavior leverages the microtask queue, which can be accessed
34
+
// via either native Promise.then or MutationObserver.
35
+
// MutationObserver has wider support, however it is seriously bugged in
36
+
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
37
+
// completely stops working after triggering a few times... so, if native
38
+
// Promise is available, we will use it:
60
39
/* istanbul ignore next, $flow-disable-line */
61
40
if (typeof Promise !== 'undefined' && isNative(Promise)) {
62
41
const p = Promise.resolve()
63
-
microTimerFunc = () => {
42
+
timerFunc = () => {
64
43
p.then(flushCallbacks)
65
-
// in problematic UIWebViews, Promise.then doesn't completely break, but
44
+
// In problematic UIWebViews, Promise.then doesn't completely break, but
66
45
// it can get stuck in a weird state where callbacks are pushed into the
67
46
// microtask queue but the queue isn't being flushed, until the browser
68
47
// needs to do some other work, e.g. handle a timer. Therefore we can
69
48
// "force" the microtask queue to be flushed by adding an empty timer.
70
49
if (isIOS) setTimeout(noop)
71
50
}
72
-
} else {
73
-
// fallback to macro
74
-
microTimerFunc = macroTimerFunc
75
-
}
76
-
77
-
/**
78
-
* Wrap a function so that if any code inside triggers state change,
79
-
* the changes are queued using a (macro) task instead of a microtask.
80
-
*/
81
-
export function withMacroTask (fn: Function): Function {
82
-
return fn._withTask || (fn._withTask = function () {
83
-
useMacroTask = true
84
-
try {
85
-
return fn.apply(null, arguments)
86
-
} finally {
87
-
useMacroTask = false
88
-
}
51
+
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
52
+
isNative(MutationObserver) ||
53
+
// PhantomJS and iOS 7.x
54
+
MutationObserver.toString() === '[object MutationObserverConstructor]'
55
+
)) {
56
+
// Use MutationObserver where native Promise is not available,
57
+
// e.g. PhantomJS, iOS7, Android 4.4
58
+
// (#6466 MutationObserver is unreliable in IE11)
59
+
let counter = 1
60
+
const observer = new MutationObserver(flushCallbacks)
61
+
const textNode = document.createTextNode(String(counter))
62
+
observer.observe(textNode, {
63
+
characterData: true
89
64
})
65
+
timerFunc = () => {
66
+
counter = (counter + 1) % 2
67
+
textNode.data = String(counter)
68
+
}
69
+
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
70
+
// Fallback to setImmediate.
71
+
// Techinically it leverages the (macro) task queue,
72
+
// but it is still a better choice than setTimeout.
73
+
timerFunc = () => {
74
+
setImmediate(flushCallbacks)
75
+
}
76
+
} else {
77
+
// Fallback to setTimeout.
78
+
timerFunc = () => {
79
+
setTimeout(flushCallbacks, 0)
80
+
}
90
81
}
91
82
92
83
export function nextTick (cb?: Function, ctx?: Object) {
@@ -104,11 +95,7 @@ export function nextTick (cb?: Function, ctx?: Object) {
104
95
})
105
96
if (!pending) {
106
97
pending = true
107
-
if (useMacroTask) {
108
-
macroTimerFunc()
109
-
} else {
110
-
microTimerFunc()
111
-
}
98
+
timerFunc()
112
99
}
113
100
// $flow-disable-line
114
101
if (!cb && typeof Promise !== 'undefined') {
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4