Skip to content

Commit 4f47f41

Browse files
committed
feat(weex): support init and reset timer functions of next-tick
* Stop using setTimeout(noop) to flush task queue in weex. * Init and reset timer functions of nextTick at beforeCreate and destroyed lifecycles of each weex page.
1 parent a50cf76 commit 4f47f41

File tree

3 files changed

+84
-42
lines changed

3 files changed

+84
-42
lines changed

src/core/util/next-tick.js

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { noop } from 'shared/util'
55
import { handleError } from './error'
6-
import { isIOS, isNative } from './env'
6+
import { isIOS, isNative, inWeex } from './env'
77

88
const callbacks = []
99
let pending = false
@@ -29,49 +29,60 @@ let microTimerFunc
2929
let macroTimerFunc
3030
let useMacroTask = false
3131

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)
32+
export function initTimerFunc () {
33+
// Determine (macro) task defer implementation.
34+
// Technically setImmediate should be the ideal choice, but it's only available
35+
// in IE. The only polyfill that consistently queues the callback after all DOM
36+
// events triggered in the same loop is by using MessageChannel.
37+
/* istanbul ignore if */
38+
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
39+
macroTimerFunc = () => {
40+
setImmediate(flushCallbacks)
41+
}
42+
} else if (typeof MessageChannel !== 'undefined' && (
43+
isNative(MessageChannel) ||
44+
// PhantomJS
45+
MessageChannel.toString() === '[object MessageChannelConstructor]'
46+
)) {
47+
const channel = new MessageChannel()
48+
const port = channel.port2
49+
channel.port1.onmessage = flushCallbacks
50+
macroTimerFunc = () => {
51+
port.postMessage(1)
52+
}
53+
} else {
54+
/* istanbul ignore next */
55+
macroTimerFunc = () => {
56+
setTimeout(flushCallbacks, 0)
57+
}
5158
}
52-
} else {
53-
/* istanbul ignore next */
54-
macroTimerFunc = () => {
55-
setTimeout(flushCallbacks, 0)
59+
60+
// Determine microtask defer implementation.
61+
/* istanbul ignore next, $flow-disable-line */
62+
if (typeof Promise !== 'undefined' && isNative(Promise)) {
63+
const p = Promise.resolve()
64+
microTimerFunc = () => {
65+
p.then(flushCallbacks)
66+
// in problematic UIWebViews, Promise.then doesn't completely break, but
67+
// it can get stuck in a weird state where callbacks are pushed into the
68+
// microtask queue but the queue isn't being flushed, until the browser
69+
// needs to do some other work, e.g. handle a timer. Therefore we can
70+
// "force" the microtask queue to be flushed by adding an empty timer.
71+
if (!inWeex && isIOS) setTimeout(noop)
72+
}
73+
} else {
74+
// fallback to macro
75+
microTimerFunc = macroTimerFunc
5676
}
5777
}
78+
initTimerFunc()
5879

59-
// Determine microtask defer implementation.
60-
/* istanbul ignore next, $flow-disable-line */
61-
if (typeof Promise !== 'undefined' && isNative(Promise)) {
62-
const p = Promise.resolve()
63-
microTimerFunc = () => {
64-
p.then(flushCallbacks)
65-
// in problematic UIWebViews, Promise.then doesn't completely break, but
66-
// it can get stuck in a weird state where callbacks are pushed into the
67-
// microtask queue but the queue isn't being flushed, until the browser
68-
// needs to do some other work, e.g. handle a timer. Therefore we can
69-
// "force" the microtask queue to be flushed by adding an empty timer.
70-
if (isIOS) setTimeout(noop)
71-
}
72-
} else {
73-
// fallback to macro
74-
microTimerFunc = macroTimerFunc
80+
export function resetTimerFunc () {
81+
callbacks.length = 0
82+
pending = false
83+
microTimerFunc = null
84+
macroTimerFunc = null
85+
useMacroTask = false
7586
}
7687

7788
/**
@@ -102,10 +113,12 @@ export function nextTick (cb?: Function, ctx?: Object) {
102113
})
103114
if (!pending) {
104115
pending = true
105-
if (useMacroTask) {
116+
if (useMacroTask && typeof macroTimerFunc === 'function') {
106117
macroTimerFunc()
107-
} else {
118+
} else if (typeof microTimerFunc === 'function') {
108119
microTimerFunc()
120+
} else {
121+
setTimeout(flushCallbacks, 0)
109122
}
110123
}
111124
// $flow-disable-line

src/platforms/weex/runtime/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import {
1414
isUnknownElement
1515
} from 'weex/util/element'
1616

17+
import internalMixin from './mixin'
18+
19+
// register internal mixin
20+
Vue.mixin(internalMixin)
21+
1722
// install platform specific utils
1823
Vue.config.mustUseProp = mustUseProp
1924
Vue.config.isReservedTag = isReservedTag

src/platforms/weex/runtime/mixin.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* @flow */
2+
/**
3+
* Internal mixin of Weex.
4+
*/
5+
import { initTimerFunc, resetTimerFunc } from 'core/util/next-tick'
6+
7+
function isRootComponent (vm: Component): boolean {
8+
return !!(vm.$options && vm.$options.el)
9+
}
10+
11+
export default {
12+
beforeCreate () {
13+
// only affect root component
14+
if (isRootComponent(this)) {
15+
initTimerFunc()
16+
}
17+
},
18+
destroyed () {
19+
// only affect root component
20+
if (isRootComponent(this)) {
21+
resetTimerFunc()
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)