Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/89.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从异步调用返回响应时出现问题_Javascript_Jquery_Asynchronous_Scope_Closures - Fatal编程技术网

Javascript 从异步调用返回响应时出现问题

Javascript 从异步调用返回响应时出现问题,javascript,jquery,asynchronous,scope,closures,Javascript,Jquery,Asynchronous,Scope,Closures,从中,我编写了以下代码: 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>'

从中,我编写了以下代码:

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;
    });
var currentSlideCount=window.imgIds.length;
对于(变量i=11;i<(currentSlideCount+10);i++){
//设置新幻灯片HTML
var newSlide='
  • 然而,我仍然在img标记上遇到一个无法将属性“src”设置为null的控制台错误,该错误是在调用其src属性之前很久创建的。据我所知,我已经正确设置了回调。为什么这仍然不起作用?

    存在两个问题:

  • 您正在控件结构内使用函数声明。您不能这样做,这是无效的;某些浏览器会尝试将其重写为函数表达式,但其他浏览器不会。函数声明仅在作用域的顶层有效,在所有控件结构之外。例如,在全局作用域或函数的顶层离子

  • 更重要的是,传递给
    foo
    的回调具有
    i
    变量的持久引用
    ,而不是创建函数时该变量的副本。因此,他们都会看到
    i
    在循环的末尾运行时的状态

  • foo
    函数移出控制结构,理想情况下对其进行参数化,特别是向其传递回调应使用的
    i
    值。例如:

    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);
    
        foo(year, month, day, i, function(result, index) {
            var newSlideId = 'apod' + index;
            document.getElementById(newSlideId).src = result;
        });
    }
    
    // GENERATE XML REQUEST
    function foo(year, month, day, index, 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, index)
                console.log(apodParse.url, index);
            }
        }
    }
    
    var currentSlideCount=window.imgIds.length;
    对于(变量i=11;i<(currentSlideCount+10);i++){
    //设置新幻灯片HTML
    
    var newSlide='
  • 首先,您在循环中声明函数
    foo
    。虽然这不会导致错误,但这是一种不好的做法。函数应该在循环之外声明

    其次,传入
    foo
    的回调函数被异步调用(即通过AJAX)。变量
    i
    在回调函数的父作用域中被赋值,在循环中被赋值。在调用回调时,循环将完成执行。调用回调时,它将在作用域链上查找以查找
    i
    的值,并返回循环中声明的d
    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中的一些作用域很有用。

    是的,这非常有意义。感谢您的解释。作用域一直是学习js最令人沮丧的事情之一。同样,您可以吗解释我将如何声明函数不在循环中?这肯定会带来其他范围问题吗?@JohnDoe您只需剪切
    函数foo{…}
    将代码的一部分粘贴到代码示例的顶部。函数的作用域不会改变。作用域是在函数级别定义的,因此将其移到循环之外不会对作用域产生任何影响。现在,在循环内部声明函数时,您每次都在反复声明相同的函数循环迭代——这对代码的性能不好。