Skip to content

Commit 02d21c2

Browse files
ahus1yyx990803
authored andcommittedMar 20, 2019
fix(core): cleanup timeouts for async components (#9649)
close #9648
1 parent bf5ceb7 commit 02d21c2

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed
 

‎src/core/vdom/helpers/resolve-async-component.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export function resolveAsyncComponent (
6565
if (owner && !isDef(factory.owners)) {
6666
const owners = factory.owners = [owner]
6767
let sync = true
68+
let timerLoading = null
69+
let timerTimeout = null
6870

6971
;(owner: any).$on('hook:destroyed', () => remove(owners, owner))
7072

@@ -75,6 +77,14 @@ export function resolveAsyncComponent (
7577

7678
if (renderCompleted) {
7779
owners.length = 0
80+
if (timerLoading !== null) {
81+
clearTimeout(timerLoading)
82+
timerLoading = null
83+
}
84+
if (timerTimeout !== null) {
85+
clearTimeout(timerTimeout)
86+
timerTimeout = null
87+
}
7888
}
7989
}
8090

@@ -121,7 +131,8 @@ export function resolveAsyncComponent (
121131
if (res.delay === 0) {
122132
factory.loading = true
123133
} else {
124-
setTimeout(() => {
134+
timerLoading = setTimeout(() => {
135+
timerLoading = null
125136
if (isUndef(factory.resolved) && isUndef(factory.error)) {
126137
factory.loading = true
127138
forceRender(false)
@@ -131,7 +142,8 @@ export function resolveAsyncComponent (
131142
}
132143

133144
if (isDef(res.timeout)) {
134-
setTimeout(() => {
145+
timerTimeout = setTimeout(() => {
146+
timerTimeout = null
135147
if (isUndef(factory.resolved)) {
136148
reject(
137149
process.env.NODE_ENV !== 'production'

‎test/unit/features/component/component-async.spec.js

+64
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,42 @@ import Vue from 'vue'
22
import { Promise } from 'es6-promise'
33

44
describe('Component async', () => {
5+
6+
const oldSetTimeout = window.setTimeout;
7+
const oldClearTimeout = window.clearTimeout;
8+
9+
// will contain pending timeouts set during the test iteration
10+
// will contain the id of the timeout as the key, and the the millisecond timeout as the value
11+
// this helps to identify the timeout that is still pending
12+
let timeoutsPending = {};
13+
14+
beforeEach(function () {
15+
// reset the timeouts for this iteration
16+
timeoutsPending = {};
17+
18+
window.setTimeout = function(func, delay) {
19+
let id = oldSetTimeout(function() {
20+
delete timeoutsPending[id];
21+
func();
22+
}, delay);
23+
timeoutsPending[id] = delay;
24+
return id
25+
};
26+
27+
window.clearTimeout = function(id) {
28+
oldClearTimeout(id);
29+
delete timeoutsPending[id];
30+
};
31+
})
32+
33+
afterEach(function () {
34+
window.setTimeout = oldSetTimeout;
35+
window.clearTimeout = oldClearTimeout;
36+
// after the test is complete no timeouts that have been set up during the test should still be active
37+
// compare stringified JSON for better error message containing ID and millisecond timeout
38+
expect(JSON.stringify(timeoutsPending)).toEqual(JSON.stringify({}))
39+
})
40+
541
it('normal', done => {
642
const vm = new Vue({
743
template: '<div><test></test></div>',
@@ -343,6 +379,34 @@ describe('Component async', () => {
343379
}, 50)
344380
})
345381

382+
it('should not have running timeout/loading if resolved', done => {
383+
const vm = new Vue({
384+
template: `<div><test/></div>`,
385+
components: {
386+
test: () => ({
387+
component: new Promise((resolve, reject) => {
388+
setTimeout(() => {
389+
resolve({ template: '<div>hi</div>' })
390+
Promise.resolve().then(() => {
391+
Vue.nextTick(next)
392+
})
393+
}, 10)
394+
}),
395+
loading: { template: `<div>loading</div>` },
396+
delay: 30,
397+
error: { template: `<div>error</div>` },
398+
timeout: 40
399+
})
400+
}
401+
}).$mount()
402+
403+
function next () {
404+
expect(vm.$el.textContent).toBe('hi')
405+
// the afterEach() will ensure that the timeouts for delay and timeout have been cleared
406+
done()
407+
}
408+
})
409+
346410
// #7107
347411
it(`should work when resolving sync in sibling component's mounted hook`, done => {
348412
let resolveTwo

0 commit comments

Comments
 (0)
Please sign in to comment.