多次调用同一JavaScript函数时前次函数执行被终止的技术问题
问题分析与解决方案
我明白你遇到的问题了——当快速多次调用ShowToast函数时,会发现之前创建的toast提示没有按预期被自动移除,甚至可能出现误删后续toast的情况?这一切都是因为全局变量ToastBtnClicks的特性导致的。
问题根源
每次调用ShowToast时,全局变量ToastBtnClicks都会自增,而setTimeout是异步执行的(它会在2秒后才触发回调)。当第一次调用的setTimeout回调执行时,ToastBtnClicks已经被后续的函数调用修改为最新值了。举个例子:
- 第一次调用
ShowToast,ToastBtnClicks变为1,创建#ToastContainerChild1 - 1秒后第二次调用,
ToastBtnClicks变为2,创建#ToastContainerChild2 - 又过1秒,第一次的
setTimeout触发,此时ToastBtnClicks是2,它会尝试删除#ToastContainerChild2,而#ToastContainerChild1会留在DOM中永远不被移除
修复方案
方案1:用闭包捕获当前计数器值
通过在函数内部创建一个局部变量保存当前的ToastBtnClicks值,确保setTimeout回调使用的是创建toast时的ID:
var ToastBtnClicks = 0; function ShowToast(ToastText){ ToastBtnClicks++; // 保存当前的计数器值,避免后续修改影响异步回调 var currentToastId = ToastBtnClicks; $('#ToastContainer').append("<div class='ToastContainerChild' id='ToastContainerChild"+ currentToastId +"'>"+ToastText+"</div><br>"); setTimeout(function(){ $("#ToastContainerChild"+ currentToastId).remove(); }, 2000); }
方案2:用ES6 let的块级作用域
如果你的环境支持ES6,let的块级作用域可以更简洁地解决这个问题:
let ToastBtnClicks = 0; function ShowToast(ToastText){ ToastBtnClicks++; let currentToastId = ToastBtnClicks; // 用模板字符串让代码更易读 $('#ToastContainer').append(`<div class='ToastContainerChild' id='ToastContainerChild${currentToastId}'>${ToastText}</div><br>`); setTimeout(function(){ $(`#ToastContainerChild${currentToastId}`).remove(); }, 2000); }
方案3:直接保存元素引用(最推荐)
完全摆脱对ID和全局计数器的依赖,直接保存创建的toast元素引用,这样既简洁又避免了ID冲突:
function ShowToast(ToastText){ // 创建元素并立即保存引用 const toastElement = $(`<div class='ToastContainerChild'>${ToastText}</div><br>`); $('#ToastContainer').append(toastElement); setTimeout(function(){ // 直接操作保存的元素,无需查找ID toastElement.remove(); }, 2000); }
这个方案不仅解决了原问题,还去掉了全局变量,让代码更模块化、更健壮。
内容的提问来源于stack exchange,提问作者Jishnu Raj
相关产品推荐
相关产品推荐

