JavaScript循环请求API插入表格重复添加相同数据问题咨询
问题根因
这是典型的异步回调闭包+var变量作用域问题,核心诱因如下:
- 你使用
var声明循环变量h与ajaxRequest,var不存在块级作用域,整个循环过程中共享同一个变量实例 - XMLHttpRequest为异步请求,回调函数触发时for循环已经执行完毕,此时
h已经等于rowData.length的值,ajaxRequest也指向最后一次循环创建的请求实例,所有回调都只会处理最后一个请求的返回结果,就会出现重复插入ID4、跳过ID3的现象。
修复方案
推荐优先使用第一种方案,兼容性可以覆盖所有主流浏览器:
方案1:将var替换为let(ES6+支持)
let具备块级作用域,每次循环都会创建独立的变量实例,回调可以正确捕获每次循环的请求和参数:
function addRow(tableName, rowData) { // 循环变量改为let声明 for (let h = 0; h < rowData.length; h++) { // 请求实例改为let声明 let ajaxRequest = new XMLHttpRequest(); ajaxRequest.onreadystatechange = function(){ if(ajaxRequest.readyState == 4){ if(ajaxRequest.status == 200){ let table = document.getElementById(tableName); let row = table.insertRow(1); var order = JSON.parse(ajaxRequest.responseText); var cell0 = row.insertCell(0); var cell1 = row.insertCell(1); var cell2 = row.insertCell(2); var cell3 = row.insertCell(3); var cell4 = row.insertCell(4); var cell5 = row.insertCell(5); var cell6 = row.insertCell(6); var cell7 = row.insertCell(7); var cell8 = row.insertCell(8); var cell9 = row.insertCell(9); var cell10 = row.insertCell(10); cell0.innerHTML = order.id; cell1.innerHTML = order.name; cell2.innerHTML = order.time; cell3.innerHTML = order.type; cell4.innerHTML = order.creamerAmount + " " + order.creamerType; cell5.innerHTML = order.sugarAmount; cell6.innerHTML = order.coffeeType; cell7.innerHTML = order.teaType; cell8.innerHTML = order.hotChocolateType; cell9.innerHTML = order.smoothieType; cell10.innerHTML = order.protein; } else { h--; } } } ajaxRequest.open('GET', 'http://localhost:13760/cafe/cafe/orders/' + rowData[h]); ajaxRequest.send(); } }
方案2:用立即执行函数(IIFE)创建独立作用域(兼容ES5及更早版本)
如果需要兼容极老旧浏览器,可以用IIFE包裹每次循环的逻辑,把当前循环的h作为参数传入独立作用域:
function addRow(tableName, rowData) { for (var h = 0; h < rowData.length; h++) { (function(currentH) { var ajaxRequest = new XMLHttpRequest(); ajaxRequest.onreadystatechange = function(){ if(ajaxRequest.readyState == 4){ if(ajaxRequest.status == 200){ let table = document.getElementById(tableName); let row = table.insertRow(1); var order = JSON.parse(ajaxRequest.responseText); var cell0 = row.insertCell(0); var cell1 = row.insertCell(1); var cell2 = row.insertCell(2); var cell3 = row.insertCell(3); var cell4 = row.insertCell(4); var cell5 = row.insertCell(5); var cell6 = row.insertCell(6); var cell7 = row.insertCell(7); var cell8 = row.insertCell(8); var cell9 = row.insertCell(9); var cell10 = row.insertCell(10); cell0.innerHTML = order.id; cell1.innerHTML = order.name; cell2.innerHTML = order.time; cell3.innerHTML = order.type; cell4.innerHTML = order.creamerAmount + " " + order.creamerType; cell5.innerHTML = order.sugarAmount; cell6.innerHTML = order.coffeeType; cell7.innerHTML = order.teaType; cell8.innerHTML = order.hotChocolateType; cell9.innerHTML = order.smoothieType; cell10.innerHTML = order.protein; } else { h--; } } } ajaxRequest.open('GET', 'http://localhost:13760/cafe/cafe/orders/' + rowData[currentH]); ajaxRequest.send(); })(h) } }
附加优化建议
- 你当前用
insertRow(1)会把新行固定插入第二行位置,异步请求返回顺序不固定,可能导致表格行顺序和rowData的顺序不一致,如需固定顺序可以等所有请求返回后统一插入,或者按索引指定插入位置。 - 错误逻辑中直接操作全局的h变量可能引发死循环,建议改用请求队列的方式处理失败重试逻辑。
内容的提问来源于stack exchange,提问作者N3ther
相关产品推荐
相关产品推荐

