通过 Javascript/jQuery 的 Ajax HEAD 请求

IT技术 javascript jquery ajax http-headers
2021-02-17 19:38:47

我似乎在提出HEAD请求和保持数组中数据的完整性方面遇到了一些问题

鉴于此片段:

var imageTemp = Array();

$('*')
    .each(function(index){
        if($(this).css('background-image') != 'none'){
            imageTemp.push($(this).css('background-image').slice(5, -2));
        }
    });

我捕获给定页面上所有背景图像的 URL。现在,尝试通过HEAD请求获取每个图像的大小Content-Length,我使用以下代码段:

var imageData = Array();

for(var i = 0; i < imageTemp.length; i++){
    ajaxSizeRequest = $.ajax({
        type: "HEAD",
        async: true,
        url: imageTemp[i],
        success: function(message){
            imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
        }
    });
}

但是,当我转储imageDatavia 时console.log,我每个元素(它应该是一个包含 URL 和内容长度的数组)最终作为[undefined, XXXX]whereXXXX总是最后请求的大小Content-Length

我很难过,虽然这似乎是一个时间/范围问题。我这里发生了某种竞争条件吗?

5个回答

问题在于,回调函数捕获的单个变量iajaxSizeRequest回调函数的所有实例都是相同的变量。我认为,如果您调用一个函数并将 index 变量传递给它,同时使用 done 处理程序的响应参数将请求变量本地范围限定为函数本身,则最终应该得到回调捕获的独立变量. 然后它应该正确引用每个数组元素和每个响应变量。

var imageData = Array();

for(var i = 0; i < imageTemp.length; i++){
    updateImageData( i );
}

function updateImageData( i )
    $.ajax({
        type: "HEAD",
        async: true,
        url: imageTemp[i],
    }).done(function(message,text,jqXHR){
        imageData.push([imageTemp[i], jqXHR.getResponseHeader('Content-Length')]);
    });
}
@EladKarako - 很老的答案,我已经更新以反映当前的最佳实践。
2021-04-16 19:38:47
非常感谢tvanfosson这就像一个魅力。updateImageData匿名以避免污染我的脚本。
2021-04-20 19:38:47
避免使用success,防止代码混乱!,.done(function(text, status, xhr){ ...... };改用。
2021-04-21 19:38:47
感谢您的更新,顺便说一句,答案是永恒的 ;) (..... 好吧.. 至少只要谷歌会在前 5 个结果中提出建议)。
2021-05-15 19:38:47

看起来你i没有完全封闭

此外,您不能使用,ajaxSizeRequest因为它也只指向一个请求(可能是最后一个,因为循环执行速度非常快)

只需success按如下方式包装您的回调函数,将引用更改为ajaxSizeRequest

success: (function(i){
   return function(data,status,xhr){
     imageData.push([imageTemp[i], xhr.getResponseHeader('Content-Length')]);
   };
})(i)

你可以把我喜欢的范围定为:

success: function(i){
    return function(message){
        imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
    }
}(i)

您有一个i由所有回调共享的变量。
由于 AJAX 是异步的,所有回调在循环完成后运行,并且它们都得到相同的i.

要解决此问题,您需要将 AJAX 调用移动到一个单独的函数中,该函数将其i作为参数。
因此,每个回调将获得一个单独的i参数。

如果有人仍然对此有疑问,并且由于这篇文章已经 5 岁了,这里有一个更“现代”的答案版本:只需使用let而不是var在原始帖子的for循环中。

信息:是否有理由在 ES6 中使用“var”关键字? 和:MDN - Let 语法