如何在setInterval定时器中正确处理jQuery post请求的响应顺序?
修复方案
异步HTTP请求固有的乱序问题可以通过以下3种可直接落地的方法解决:
方案1:序列号比对(改动最小,无需调整原有请求逻辑)
每次发起请求时携带自增的序列号,后端原样返回,前端仅更新序列号大于当前已渲染最大值的响应:
let getStatusIV; // 存储当前最新的请求序列号和已渲染的最大序列号 let reqSeq = 0; let renderedSeq = 0; getStatusIV = setInterval( () => { // 每次请求序列号自增 const currentSeq = ++reqSeq; let data = { action: 'get_products_status', import_id: importId, seq: currentSeq // 传递给后端 }; $.post( ajaxurl, data, function () { } ).done( response => { if (response.success && response.data) { // 仅当当前响应的序列号大于已渲染的最大序列号时才更新UI if (response.seq > renderedSeq) { renderedSeq = response.seq; showLoadingSpinner( '#wpcontent', response.data ); } } } ) }, 500 );
后端仅需要在返回的响应体中新增seq字段,把前端传过来的序列号原样返回即可。
方案2:请求串行化(从根源避免并发乱序)
放弃固定间隔的setInterval,改为上一个请求完成后再间隔500ms发起下一个请求,避免同时存在多个未完成的请求:
let stopPolling = false; // 递归发起请求 function pollStatus() { if (stopPolling) return; let data = { action: 'get_products_status', import_id: importId }; $.post( ajaxurl, data, function () { } ).done( response => { if (response.success && response.data) { showLoadingSpinner( '#wpcontent', response.data ); } } ).always(() => { // 不管请求成功失败,都等待500ms再发起下一次请求 setTimeout(pollStatus, 500); }); } // 启动轮询 pollStatus(); // 进度完成后赋值 stopPolling = true 即可停止轮询
这个方案还可以避免无效的并发请求,适合绝大多数轮询场景。
方案3:进度值校验(无需调整接口和请求参数)
如果后端返回的进度信息里包含已处理的数量数值,前端可以提取该数值,仅渲染数值大于当前已展示数值的响应:
let getStatusIV; // 存储当前已渲染的最大处理数 let maxProcessed = 0; getStatusIV = setInterval( () => { let data = { action: 'get_products_status', import_id: importId }; $.post( ajaxurl, data, function () { } ).done( response => { if (response.success && response.data) { // 从返回的文本中提取已处理数量,例如从"Processed 20 of 700 products"中提取20 const processed = parseInt(response.data.match(/Processed (\d+) of/)[1]); if (processed > maxProcessed) { maxProcessed = processed; showLoadingSpinner( '#wpcontent', response.data ); } } } ) }, 500 );
这个方案不需要修改后端接口,仅前端做过滤即可。
内容的提问来源于stack exchange,提问作者Mr. Jo
相关产品推荐
相关产品推荐

