Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 fix the issue which an auto closed dialog with a timer would not be cleared after app unmounted #360

Merged
merged 3 commits into from
Mar 30, 2020

Conversation

kuitos
Copy link
Member

@kuitos kuitos commented Mar 29, 2020

@kuitos kuitos requested review from howel52 and Deturium March 29, 2020 16:27
@howel52
Copy link
Collaborator

howel52 commented Mar 29, 2020

这个可以有单测 case 么

@kuitos
Copy link
Member Author

kuitos commented Mar 29, 2020

我加下

@Deturium
Copy link
Contributor

所以现在是在卸载的时候 提前 执行这个 timer 了?
明显这样会引发别的问题的,这个估计会是自定义需求比较多的 hijacker 了吧 Orz...

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

明显这样会引发别的问题的

比如什么问题?

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

单测加了 @howel52

@howel52
Copy link
Collaborator

howel52 commented Mar 30, 2020

比如什么问题?

可能是会出一些问题,比如 slave 有个 setTimeout(() => router.push('/b'), 10000),同时在页面中倒计时展示说 s 秒后自动跳转到xxx。 这时候切 slave (free) 的话,貌似就路由就直接 push '/b'

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

改路由的场景是有点蛋疼。
但我理解这种场景是偏业务的,这个时候应该是需要应用自己在 willUnmount 里 clearTimerout。目前比较多的问题是如果不自动清理,antd 的 message.open(<>, 5000) 这种场景,应用切出后弹层不会自动关闭。

@howel52
Copy link
Collaborator

howel52 commented Mar 30, 2020

还想到一个可能比较小众的场景,如果有人在 class component 里用 setTimeout 去模拟 setInterval 的话(同时 timer 可能是记在 实例中),这块貌似会有点问题

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

setTimeout 模拟 setInterval

这个确实更蛋疼。
但是也是有解的,一条路走到黑,直接 handler.toString() 判断里面有没有再调用 setTimeout 跟 setInterval,有的话就不再调用 handler 直接 clear 了。。

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

还有一种解法,执行 handler 之前先把 window.setTimeout = noop,这样就能避免递归 setTimeout 了..

@howel52
Copy link
Collaborator

howel52 commented Mar 30, 2020

直接 handler.toString() 判断里面有没有再调用 setTimeout 跟 setInterval

这种可能并不能完全解决问题,handler 里不一定是直接调 setTimeout 的,可能通过其他方法包了一下

执行 handler 之前先把 window.setTimeout = noop

这种的话 handler 执行过程中是不是有可能会把上下文里正常的 setTimeout 给 miss 了

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

这种的话 handler 执行过程中是不是有可能会把上下文里正常的 setTimeout 给 miss 了

handler 执行中如果调用了 setTimeout 实际是调用了 noop 这应该是符合预期的。handler 调用完之后 setTimeout 会重置成正常状态

@howel52
Copy link
Collaborator

howel52 commented Mar 30, 2020

这种的话 handler 执行过程中是不是有可能会把上下文里正常的 setTimeout 给 miss 了

const timer1 = setTimeout(async() => {
   await sleep(1000)
}, 1000);

const timer2 = setTimeout(async() => {
   setTimeout(xxxxx) 
}, 1500);

比如 timer1、timer2 这种情况,timer1 handler 执行的过程中,timer2 正常的 setTimeout 被 noop 了。 而预期应该是 timer1 handler 执行过程中,只避免 timer1 中的 setTimeout 被递归

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

所有未被 clear 的 timeout 在 free 的时候都会被调用一次 handler,这个过程是同步的,也就是这期间 handler 里如果还有 setTimeout 调用的话都是无效的,这应该是符合预期的,不然就又要重复 记录 timer -> 看是否清除 -> 自动清除 的过程。

window.setTimeout = noop;
timers.forEach(({ handler, id, args }) => {
  // clear the timers and execute its handler to avoid uncleared effects
  // such as antd auto closing message
  handler(...args);
  window.clearTimeout(id);
});

window.setTimeout = rawWindowTimeout;
window.clearTimeout = rawWindowClearTimout;

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

想了下干脆 setTimeout 不处理了,只处理 setInterval(直接 clear 也不调 handler)。
antd 的问题在 umi plugin 里直接 message.destroy() 帮用户手动清理就可以了。

@kuitos
Copy link
Member Author

kuitos commented Mar 30, 2020

恢复到之前的场景,自动清理未执行的 timeout 跟 interval。antd message 之类的场景在 umi 插件及 faq 里给出解决方案。

@howel52
Copy link
Collaborator

howel52 commented Mar 30, 2020

LGTM

@kuitos kuitos merged commit bb54d95 into master Mar 30, 2020
@kuitos kuitos deleted the bug/timer-resolve branch March 30, 2020 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants