JavaScript循环中AJAX仅执行一次且i值异常为4的问题排查
问题拆解与解决方案
这是个非常典型的异步请求+闭包作用域陷阱,我来帮你一步步理清楚问题所在:
为什么输出的i是4?
你用var声明的i是函数级作用域(在全局或当前函数内有效),而$.get是异步AJAX请求——也就是说,循环的同步代码会先全部执行完,AJAX的回调函数要等请求完成后才会触发。
当循环执行时:
- 第一次循环:
i=1,执行console.log(1),发送第一个AJAX请求(此时回调还没触发) - 第二次循环:
i=2,执行console.log(2),发送第二个AJAX请求 - 第三次循环:
i=3,执行console.log(3),发送第三个AJAX请求 - 循环结束:
i自增到4,此时i<=qtt(3)不成立,循环退出
等三个AJAX请求陆续完成,回调函数执行时,它们引用的都是同一个i变量,而此时i已经是4了,所以每次回调都会输出test 4。
为什么看起来回调只执行了一次?
其实你的代码里三个AJAX回调都会执行,只是因为异步的特性,它们的输出会在循环的同步输出(1、2、3)之后出现。如果你的控制台把相同的输出合并显示了,就会看起来像只执行了一次。你可以在回调里加上请求的标识(比如自定义的序号),就能看到三次回调的执行了。
解决方案
这里有几种常用的修复方式:
1. 用let代替var声明i
ES6的let会创建块级作用域,每次循环都会生成一个独立的i变量,回调函数会捕获当前循环的i值:
var qtt = 3; for (let i = 1; i <= qtt; i++) { console.log(i); $.get("/set-serie", function(seriedata) { console.log('test ' + i); }); }
2. 使用立即执行函数表达式(IIFE)捕获每次的i
在不支持ES6的环境下,可以用IIFE创建独立作用域:
var qtt = 3; for (var i = 1; i <= qtt; i++) { console.log(i); (function(currentI) { $.get("/set-serie", function(seriedata) { console.log('test ' + currentI); }); })(i); }
3. 使用forEach循环遍历
把循环改成forEach,利用其回调的作用域特性:
var qtt = 3; Array.from({length: qtt}, (_, index) => index + 1).forEach(function(i) { console.log(i); $.get("/set-serie", function(seriedata) { console.log('test ' + i); }); });
这样修改后,每个AJAX回调都会输出对应的i值(1、2、3),你也能清晰看到三次回调的执行结果了。
内容的提问来源于stack exchange,提问作者user3242861
相关产品推荐
相关产品推荐

