为何循环中$.get()的回调仅执行最后一次?技术求助
问题:循环中仅最后一个设备的AJAX回调执行
我在程序中编写了如下代码,本意是遍历所有设备,通过$.get()请求设备缩略图,根据请求成功或失败执行对应操作。但从控制台日志发现,循环中每个设备都打印了before get日志,却仅最后一个设备的done/always回调日志被输出。
控制台日志
before get: efbekmtfgjyz9pr_0_0 before get: gu2u1hnspgo2vhk_1_0 done get: gu2u1hnspgo2vhk_1_0 always get: gu2u1hnspgo2vhk_1_0
代码片段
var deviceIx = 0; while (deviceIx < service.devices.length) { var devId = buildUniqueHTMLId( device.jid + "_" + deviceIx + "_" + serviceIx ); console.log("before get: " + devId); $.get(device.thumbnail).done(function () { console.log("done get: " + devId); $('.devicelist #deviceImg-' + devId).attr("src", device.thumbnail); var img = device.thumbnail; var caption = "FRONT"; $("#deviceImagesCarousel .carousel-inner").append("<div class='carousel-item'><img class='d-block w-100' src='" + img + "' alt='" + img + "'><div class='carousel-caption'>" + caption +"</div></div>"); $("#deviceImagesCarousel .carousel-indicators").append("<li data-target='#deviceImagesCarousel' data-slide-to='0' ></li>"); $('#deviceImagesCarousel .carousel-inner .carousel-item').first().addClass('active'); $('#deviceImagesCarousel .carousel-indicators li').first().addClass('active'); }).fail(function () { console.log("fail get: " + devId); $('.devicelist #deviceImg-' + devId).attr("src", 'script/iopsys/devicemanager/images/hardwareversions/gateway/na_t.png'); $("#deviceImagesCarousel .carousel-inner").append("<div class='carousel-item'><img class='d-block w-100' src='script/iopsys/devicemanager/images/hardwareversions/gateway/na_t.png' alt='First slide'></div>"); $("#deviceImagesCarousel .carousel-indicators").append("<li data-target='#deviceImagesCarousel' data-slide-to='0' ></li>"); $('#deviceImagesCarousel .carousel-inner .carousel-item').first().addClass('active'); $('#deviceImagesCarousel .carousel-indicators li').first().addClass('active'); }).always(function() { console.log("always get: " + devId); $('.devicelist #deviceImg-' + devId).attr("src", device.thumbnail); });
原因分析
这是JavaScript闭包的经典问题:
$.get()是异步请求,回调函数(done/fail/always)会在请求完成后才执行,但while循环是同步执行的,会快速遍历完所有设备。- 循环里的
devId和device变量属于函数作用域(while没有块级作用域),当回调函数最终触发时,循环已经结束,这两个变量的值已经被覆盖为最后一次循环的设备数据。 - 所以所有回调函数都会引用最后一个设备的变量值,自然只会打印最后一个设备的日志,操作也只会针对最后一个设备生效。
内容的提问来源于stack exchange,提问作者Amber Akkermans
相关产品推荐
相关产品推荐

