多倒计时器场景下如何终止对应正确的Web Worker实例?
问题分析
你的核心问题在于全局变量w被重复覆盖了!每次调用startTimer时,你都把新创建的Worker赋值给全局的w,导致所有计时器的onmessage回调里,w最终指向的都是最后一个创建的Worker实例。所以不管哪个计时器到期,终止的都是最后那个Worker。
修复方案
把Worker的引用改成局部变量,确保每个startTimer调用都持有自己独立的Worker实例。同时可以用一个对象来映射每个timerId对应的Worker,方便后续管理(比如手动终止)。
以下是修改后的完整代码:
$(document).ready(function() { // 用一个对象存储timerId和对应的Worker实例,方便管理 const workerMap = {}; $('.frequency-item').each(function(i, e) { const children = $(e).children(); const observationLengthInMinutesId = children[1].id; const timerId = children[3].id; startTimer(observationLengthInMinutesId, timerId, workerMap); }); }); function startTimer(observationLengthInMinutesId, timerId, workerMap) { // 用let声明局部变量w,避免全局覆盖 let w = null; if (typeof(Worker) !== "undefined") { if (w == null) { w = new Worker("/js/simple-timer.js"); // 把Worker实例存入映射表 workerMap[timerId] = w; w.postMessage($('#' + observationLengthInMinutesId).val()); } w.onmessage = function(event) { $('#' + timerId).text(event.data); if (event.data === '00:00') { // 终止当前对应的Worker实例 w.terminate(); // 从映射表中移除,避免内存泄漏 delete workerMap[timerId]; } }; // 可选:监听Worker错误,及时清理资源 w.onerror = function(error) { console.error(`Worker error for timer ${timerId}:`, error); w.terminate(); delete workerMap[timerId]; }; } else { $('#' + timerId).text("Sorry, your browser does not support Web Workers ..."); } }
关键修改点
- 局部变量替代全局变量:用
let w在startTimer内部声明Worker变量,每个计时器调用都会创建独立的引用,不会被后续调用覆盖。 - Worker映射表:新增
workerMap对象存储每个timerId对应的Worker实例,不仅能确保终止正确的Worker,还方便后续如果需要手动终止某个计时器(比如用户点击取消按钮)时快速找到对应的Worker。 - 清理映射表:终止Worker后从
workerMap中删除对应条目,避免内存泄漏。
这样修改后,每个计时器到期时,都会精准终止自己对应的Web Worker实例啦!
内容的提问来源于stack exchange,提问作者Gianluca78
相关产品推荐
相关产品推荐

