js 关于轮询查询,里面离开后仍然执行,导致其他页面异常或数据紊乱
背景:
ASP.NET WebAPI项目
将页面cshtml填充到RenderBody()的方式来实现单页面应用
出现异常的情况:
通过定时器setInterval来实现定时对table 数据的填充(setInterval的特点是不管前一次是否执行,只要到时间了就会执行下一次)
关键代码
table标签
<table class="table table-bordered table-checkable text-nowrap tablecolor" id="t_table"></table>
table的定义
var initTable; var DefinitionTable = { init: () => { initTable = $("#t_table").dataTable({ // language: lang, //提示信息 dom: "<'row'<'col-sm-12'tr>>\n\t\t\t<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7 dataTables_pager'lp>>", responsive: true, processing: false, serverSide: true, searching: false, orderMulti: false, ordering: true, aLengthMenu: [10, 20, 50, 70, 90], iDisplayLength: 20, stripeClasses: ['ou', 'ed'], columnDefs: columnDefs, aaSorting: aaSorting, "fnDrawCallback": function () { initPageGo(); }, ajax: (data, callback, settings) => { Request.Get("@path", params, (result) => { if (result.code === Success) { callback(result.data); } else { ShowDialog(result.message); } }, (error) => { }); }, //列表表头字段 columns: columns, }).api();
定时刷新
//开始刷新 var startRefresh= function () { stopRefresh(); setInterval(function f() { if (!initTable) DefinitionTable.init(); else initTable.draw(false); }, 20000); }; //停止刷新 var stopRefresh = function () { var timerId = setTimeout(function () { }, 0); while (timerId > 0) { clearInterval(timerId); timerId--; } }; $(() => { initTable = null; DefinitionTable.init(); startRefresh(); });
这种方式出现的异常情况:
进入其他页面后,这个定时刷新仍在执行,导致在同类的查询页面(页面显示内容差不多,只是因为查询条件不同,展现的数据不同),跳转的这个页面有个特殊请款,进入页面不会查询,也不会开启定时查询,但现在是进入页面后就会查询出数据也会定时刷新,观察了一下http请求,发现是上一个页面的定时查询。
原因分析:
可能得原因在上一个页面离开后js不会销毁,没有手动干预的情况,开始执行了就会一直执行,导致这个定时任务一直执行。
注:由于这是一个单页面应用,还不能通过页面关闭事件去处理。
根据以上情况改用下面的方式
使用setTimeout来定时查询,当上一次执行成功了再次调用setTimeout来定时执行下一次的查询,并记录下setTimeout的值,为销毁做准备,每次执行setTimeout时删除上一次没执行的setTimeout,其他页面在进入页面时就先删除setTimeout防止其他页面的定时执行影响本页的数据。
var initTable; var DefinitionTable = { init: () => { initTable = $("#t_table").dataTable({ // language: lang, //提示信息 dom: "<'row'<'col-sm-12'tr>>\n\t\t\t<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7 dataTables_pager'lp>>", responsive: true, processing: false, serverSide: true, searching: false, orderMulti: false, ordering: true, aLengthMenu: [10, 20, 50, 70, 90], iDisplayLength: 20, stripeClasses: ['ou', 'ed'], columnDefs: columnDefs, aaSorting: aaSorting, "fnDrawCallback": function () { initPageGo(); }, ajax: (data, callback, settings) => { Request.Get("@path", params, (result) => { if (result.code === Success) { startRefresh(); callback(result.data); } else { ShowDialog(result.message); } }, (error) => { }); }, //列表表头字段 columns: columns, }).api(); //开始刷新 var startRefresh= function () { stopRefresh(); var timeOutId = setTimeout(function f() { if (!initTable) DefinitionTable.init(); else { initTable.draw(false); } }, 20000); sessionStorage.setItem("setTimeoutId", timeOutId); }; //停止刷新 var stopRefresh= function () { var id = sessionStorage.getItem("setTimeoutId"); if (id) { clearTimeout(id) } }; $(() => { //关闭其他页面的定时刷新 stopRefresh(); initTable = null; DefinitionTable.init(); });
其他所有可能从这些定时页面直接跳过去的都要加上停止刷新的逻辑
//停止刷新 var stopRefresh= function () { var id = sessionStorage.getItem("setTimeoutId"); if (id) { clearTimeout(id) } }; $(() => { //关闭其他页面的定时刷新 stopRefresh(); });
这种方式解决了问题,但是需要对相关的多个页面要同时处理,处理起来有点繁琐,页面多的情况还可能漏处理,最好是能在定时任务自己的页面处理好这些问题
在方式二的基础上,通过判定要填充数据的元素是否存在,存在就执行刷新填充数据,否则不予处理
这中方式的前提保证判定元素的存在条件的唯一性,本次就通过id保证唯一性
var initTable; var DefinitionTable = { init: () => { initTable = $("#t_table").dataTable({ // language: lang, //提示信息 dom: "<'row'<'col-sm-12'tr>>\n\t\t\t<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7 dataTables_pager'lp>>", responsive: true, processing: false, serverSide: true, searching: false, orderMulti: false, ordering: true, aLengthMenu: [10, 20, 50, 70, 90], iDisplayLength: 20, stripeClasses: ['ou', 'ed'], columnDefs: columnDefs, aaSorting: aaSorting, "fnDrawCallback": function () { initPageGo(); }, ajax: (data, callback, settings) => { Request.Get("@path", params, (result) => { if (result.code === Success) { if ($("#t_table").html()) { startRefresh(); callback(result.data); } } else { ShowDialog(result.message); } }, (error) => { }); }, //列表表头字段 columns: columns, }).api(); //开始刷新 var startRefresh= function () { setTimeout(function f() { if ($("#t_table").html()) { if (!initTable) DefinitionTable.init(); else { initTable.draw(false); } } }, 20000); }; $(() => { initTable = null; DefinitionTable.init(); });