如何在jQuery Ajax的success回调中正确递增变量并访问其值?
问题分析与解决方案
你的问题核心是AJAX异步执行+变量作用域导致的闭包陷阱:
- 默认情况下
$.ajax是异步的,循环会快速遍历完所有FormData项,把所有AJAX请求都发出去,此时ii已经变成3了。等AJAX的success回调触发时,所有回调引用的都是这个最终的ii值,自然看不到正确的递增效果。 - 用
var声明的ii属于upload函数的全局作用域,所有循环迭代和回调共享同一个变量,没有独立的作用域保存每一次迭代的ii值。
正确的实现方式
你需要给每一次循环迭代的ii和name创建独立的作用域,同时把ii++移到AJAX请求之前(满足你“在$.ajax调用前访问到它”的需求),具体有两种简单的实现方式:
方式一:使用let声明循环变量(ES6+推荐)
利用let的块级作用域特性,让每一次循环迭代都拥有独立的ii和name变量:
<html> <span id="spanstatus"></span><br> <script src="../js/jquery-1.12.4.min.js"></script> <script> var data = new FormData(); data.append('test', 'a'); data.append('test1', 'b'); data.append('test2', 'c'); function upload() { $('#spanstatus').html(''); let ii=0; for(let [name, value] of data) { let currentIi = ii; $('#spanstatus').append('<i>Uploading <b>"'+name+'"</b></i>...<span id="spanupload_'+currentIi+'">'+currentIi+'</span><br>'); $.ajax({ type:'POST', method: 'POST', timeout:2000, url:'upload.php?val='+value, dataType: "json", data: value, contentType: false, cache: false, processData:false, success:function(response){ $('#spanupload_'+currentIi).html(currentIi+' OK'); alert(currentIi+'ok='+name); } }); ii++; } } $(document).ready(function(){ upload(); }); </script> </body> </html>
方式二:使用立即执行函数(兼容旧版JS)
如果需要兼容不支持ES6的环境,可以用立即执行函数(IIFE)为每一次迭代创建独立作用域:
<html> <span id="spanstatus"></span><br> <script src="../js/jquery-1.12.4.min.js"></script> <script> var data = new FormData(); data.append('test', 'a'); data.append('test1', 'b'); data.append('test2', 'c'); function upload() { $('#spanstatus').html(''); var ii=0; for(var [name, value] of data) { (function(currentIi, currentName) { $('#spanstatus').append('<i>Uploading <b>"'+currentName+'"</b></i>...<span id="spanupload_'+currentIi+'">'+currentIi+'</span><br>'); $.ajax({ type:'POST', method: 'POST', timeout:2000, url:'upload.php?val='+value, dataType: "json", data: value, contentType: false, cache: false, processData:false, success:function(response){ $('#spanupload_'+currentIi).html(currentIi+' OK'); alert(currentIi+'ok='+currentName); } }); })(ii, name); ii++; } } $(document).ready(function(){ upload(); }); </script> </body> </html>
关键改动说明
- 把
ii++移到AJAX请求代码块之外:确保在发送AJAX请求前,ii已经完成递增(或者说,当前迭代的ii值已经被保存下来),满足你“在$.ajax调用前访问到它”的需求。 - 为每一次迭代创建独立作用域:无论是用
let还是立即执行函数,都是为了让每个AJAX的success回调能引用到当前迭代的ii和name值,而不是循环结束后的最终值。
内容的提问来源于stack exchange,提问作者Hida
相关产品推荐
相关产品推荐

