1
+ /* globals MutationObserver */
2
+
1
3
// can we use __proto__?
2
4
export const hasProto = '__proto__' in { }
3
5
@@ -14,6 +16,7 @@ const UA = inBrowser && window.navigator.userAgent.toLowerCase()
14
16
export const isIE = UA && UA . indexOf ( 'trident' ) > 0
15
17
export const isIE9 = UA && UA . indexOf ( 'msie 9.0' ) > 0
16
18
export const isAndroid = UA && UA . indexOf ( 'android' ) > 0
19
+ export const isIOS = UA && / i p h o n e | i p a d | i p o d | i o s / . test ( UA )
17
20
18
21
let transitionProp
19
22
let transitionEndEvent
@@ -49,6 +52,11 @@ export {
49
52
animationEndEvent
50
53
}
51
54
55
+ /* istanbul ignore next */
56
+ function isNative ( Ctor ) {
57
+ return / n a t i v e c o d e / . test ( Ctor . toString ( ) )
58
+ }
59
+
52
60
/**
53
61
* Defer a task to execute it asynchronously. Ideally this
54
62
* should be executed as a microtask, so we leverage
@@ -60,34 +68,55 @@ export {
60
68
*/
61
69
62
70
export const nextTick = ( function ( ) {
63
- var callbacks = [ ]
64
- var pending = false
65
- var timerFunc
71
+ const callbacks = [ ]
72
+ let pending = false
73
+ let timerFunc
74
+
66
75
function nextTickHandler ( ) {
67
76
pending = false
68
- var copies = callbacks . slice ( 0 )
69
- callbacks = [ ]
70
- for ( var i = 0 ; i < copies . length ; i ++ ) {
77
+ const copies = callbacks . slice ( 0 )
78
+ callbacks . length = 0
79
+ for ( let i = 0 ; i < copies . length ; i ++ ) {
71
80
copies [ i ] ( )
72
81
}
73
82
}
74
83
75
- /* istanbul ignore else */
76
- if ( inBrowser && window . postMessage &&
77
- ! window . importScripts && // not in WebWorker
78
- ! ( isAndroid && ! window . requestAnimationFrame ) // not in Android <= 4.3
79
- ) {
80
- const NEXT_TICK_TOKEN = '__vue__nextTick__'
81
- window . addEventListener ( 'message' , e => {
82
- if ( e . source === window && e . data === NEXT_TICK_TOKEN ) {
83
- nextTickHandler ( )
84
- }
84
+ // the nextTick behavior leverages the microtask queue, which can be accessed
85
+ // via either native Promise.then or MutationObserver.
86
+ // MutationObserver has wider support, however it is seriously bugged in
87
+ // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
88
+ // completely stops working after triggering a few times... so, if native
89
+ // Promise is available, we will use it:
90
+ /* istanbul ignore if */
91
+ if ( typeof Promise !== 'undefined' && isNative ( Promise ) ) {
92
+ var p = Promise . resolve ( )
93
+ var noop = function ( ) { }
94
+ timerFunc = ( ) => {
95
+ p . then ( nextTickHandler )
96
+ // in problematic UIWebViews, Promise.then doesn't completely break, but
97
+ // it can get stuck in a weird state where callbacks are pushed into the
98
+ // microtask queue but the queue isn't being flushed, until the browser
99
+ // needs to do some other work, e.g. handle a timer. Therefore we can
100
+ // "force" the microtask queue to be flushed by adding an empty timer.
101
+ if ( isIOS ) setTimeout ( noop )
102
+ }
103
+ } else if ( typeof MutationObserver !== 'undefined' ) {
104
+ // use MutationObserver where native Promise is not available,
105
+ // e.g. IE11, iOS7, Android 4.4
106
+ var counter = 1
107
+ var observer = new MutationObserver ( nextTickHandler )
108
+ var textNode = document . createTextNode ( String ( counter ) )
109
+ observer . observe ( textNode , {
110
+ characterData : true
85
111
} )
86
112
timerFunc = ( ) => {
87
- window . postMessage ( NEXT_TICK_TOKEN , '*' )
113
+ counter = ( counter + 1 ) % 2
114
+ textNode . data = String ( counter )
88
115
}
89
116
} else {
90
- timerFunc = ( typeof global !== 'undefined' && global . setImmediate ) || setTimeout
117
+ // fallback to setTimeout
118
+ /* istanbul ignore next */
119
+ timerFunc = setTimeout
91
120
}
92
121
93
122
return function ( cb , ctx ) {
@@ -103,7 +132,7 @@ export const nextTick = (function () {
103
132
104
133
let _Set
105
134
/* istanbul ignore if */
106
- if ( typeof Set !== 'undefined' && Set . toString ( ) . match ( / n a t i v e c o d e / ) ) {
135
+ if ( typeof Set !== 'undefined' && isNative ( Set ) ) {
107
136
// use native Set when available.
108
137
_Set = Set
109
138
} else {
0 commit comments