Set Interval ID事件调用时变更致并发轮询问题排查
问题分析与解决方案:定时器ID被覆盖导致多轮询并发问题
你碰到的这个问题太典型了——连续点击同一按钮时,旧的定时器ID被新创建的定时器ID覆盖,导致后续调用clearInterval时只能清除最新的那个定时器,之前的旧定时器就会在后台偷偷运行,最终出现多个轮询并发的情况。
核心问题拆解
举个例子:连续点击两次P1按钮,第一次点击生成的定时器ID存在this.interval1里,第二次点击时直接用新的ID覆盖了它,这时候旧定时器还在运行,但你手里已经没有它的ID了。之后点击P2时,clearInterval(this.interval1)只能清除第二次的定时器,第一次的那个就成了“孤儿”,继续在后台打印Polling 1.。
修复方案
解决思路很简单:每次启动新的轮询前,先清除当前进程自己的旧定时器,再清除其他进程的定时器,最后创建新的定时器。这样不管点击多少次同一按钮,旧的定时器都会被及时清理,不会遗留。
修改后的完整代码
class Handler { constructor () { this.interval1 = 0; this.interval2 = 0; this.interval3 = 0; } getToken(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } // 抽离清除其他定时器的逻辑,让代码更整洁 clearOtherIntervals(current) { if (current !== 'one') clearInterval(this.interval1); if (current !== 'two') clearInterval(this.interval2); } process_one () { // 先清除自身旧定时器 clearInterval(this.interval1); // 清除其他进程的定时器 this.clearOtherIntervals('one'); this.interval1 = setInterval(function() { console.log(" Polling 1. ") },300); } async process_two () { // 先清除自身旧定时器 clearInterval(this.interval2); // 清除其他进程的定时器 this.clearOtherIntervals('two'); var scope_obj = this; this.interval2 = setInterval(async function() { console.log(" Polling 2. "); var data = await scope_obj.process_three(); }, 500); } async process_three () { return axios( { url: "", data:{"data":"LOL"}, headers : { 'X-CSRFToken': this.getToken('csrftoken'), 'Content-Type': 'application/x-www-form-urlencoded' } } ) } } let event = new Handler(); $("#p1").click(function() { console.log("P1 started.") event.process_one (); }) $("#p2").click(async function() { console.log("P2 started.") event.process_two (); }) $("#p3").click(function() { console.log("P3 started.") event.process_three (); })
<div class="row"> <div class="col-lg-12"> <button type="button" class="btn btn-warning" id="p1">P1</button> <button type="button" class="btn btn-warning" id="p2">P2</button> <button type="button" class="btn btn-warning" id="p3">P3</button> </div> </div>
额外优化建议
- 如果后续要增加更多进程,建议用一个对象来管理所有定时器ID,比如
this.intervals = { one: 0, two: 0 },这样管理起来更灵活,也不容易出错。 - 对于
process_three,如果它不需要轮询,其实不需要给它分配interval变量,当前的逻辑是没问题的。
内容的提问来源于stack exchange,提问作者prat
相关产品推荐
相关产品推荐

