编程语言
首页 > 编程语言> > javascript-无法从异步调用返回响应

javascript-无法从异步调用返回响应

作者:互联网

这个问题已经在这里有了答案:            >            JavaScript closure inside loops – simple practical example                                    43个
来自this questionFollowing 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