javascript-无法从异步调用返回响应
作者:互联网
这个问题已经在这里有了答案: > JavaScript closure inside loops – simple practical example 43个
来自this question的Following this fiddle,我编写了这段代码:
var currentSlideCount = window.imgIds.length;
for (var i = 11; i < (currentSlideCount + 10); i++) {
// SET UP NEW SLIDE HTML
var newSlide = '<li><img id="apod' + i + '" class="rounded-corners apod-image"></li>';
$('#lightSlider').append(newSlide);
window.imgIds.push('apod'+i);
console.log(window.imgIds);
// GENERATE DATE
var date = new Date();
date.setDate(date.getDate() - i);
var day = date.getDate();
var month = date.getMonth();
var year = date.getFullYear();
console.log(year + "-" + month + "-" + day);
// GENERATE XML REQUEST
function foo(callback) {
var apodUrl = "https://api.nasa.gov/planetary/apod?concept_tags=True&date=" + year + "-" + month + "-" + day;
var apodXml = new XMLHttpRequest();
apodXml.open('GET', apodUrl, true);
apodXml.send(null);
// WHEN REQUEST IS READY
apodXml.onreadystatechange=function() {
if (apodXml.readyState==4 && apodXml.status==200) {
var apodParse = JSON.parse(apodXml.responseText);
callback(apodParse.url)
console.log(apodParse.url);
}
}
}
foo(function(result) {
var newSlideId = 'apod' + i;
document.getElementById(newSlideId).src = result;
});
但是,在调用src属性之前创建的img标签上,仍然出现null控制台错误的Cannot set属性’src’的错误.据我了解,我已经正确设置了回调.为什么这仍然不起作用?
解决方法:
首先,您要在循环中声明函数foo.虽然这不会导致错误,但是这是错误的做法.该函数应在循环外部声明.
其次,传递给foo的回调函数是异步调用的(即通过AJAX).在回调函数的父作用域和循环中为变量i分配一个值.循环将在调用回调时完成执行.调用回调时,它将在范围链中查找i的值,并在循环中找到i. i将等于循环条件i <的循环中的最终值. (currentSlideCount 10)评估为false,并且不会继续.
尽管这可能很难理解,但是您可以通过添加alert(i)来了解我的意思.到回调函数:
foo(function(result) {
alert(i);
var newSlideId = 'apod' + i;
document.getElementById(newSlideId).src = result;
});
您可能会惊讶地看到警报将始终为i显示相同的值.
要解决此问题,您需要使用立即执行的函数来创建新的作用域,在该作用域中,按值传递i作为所需的适当值.
更改此:
foo(function(result) {
var newSlideId = 'apod' + i;
document.getElementById(newSlideId).src = result;
});
对此:
foo(
(function(i) {
return function(result) {
var newSlideId = 'apod' + i;
document.getElementById(newSlideId).src = result;
}
})(i)
);
在JavaScript中,作用域是在功能级别上描述的.通过使用立即执行的函数,您将添加一个新的作用域,在该作用域中,按值将i传递给循环的当前迭代.
JavaScript中的变量作用域很难理解,而且您的问题会在更复杂的情况之一中出现.您可能会发现,复习JavaScript中的other explanations范围是很有用的.
标签:scope,closures,asynchronous,javascript,jquery 来源: https://codeday.me/bug/20191120/2041593.html