web-dev-qa-db-fra.com

Ajax HEAD demande via Javascript/jQuery

Il semble que certains problèmes me empêchent de formuler des requêtes HEAD et de préserver l'intégrité des données d'un tableau.

Étant donné cet extrait:

var imageTemp = Array();

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

Je capture les URL de toutes les images d'arrière-plan sur une page donnée. Maintenant, en essayant de saisir la taille de chaque image via les requêtes HEAD pour Content-Length, j'utilise cet extrait:

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')]);
        }
    });
}

Cependant, lorsque je vide imageData via console.log, chaque élément (qui devrait être un tableau contenant l'URL et la longueur du contenu) se termine par [undefined, XXXX]XXXX est toujours la taille du dernier Content-Length demandé.

Je suis perplexe, bien que cela semble être une question de timing/portée. Ai-je une sorte de condition de course qui se passe ici?

14
Dan Lugg

Le problème est que les variables uniques i et ajaxSizeRequest capturées par la fonction de rappel sont les mêmes pour toutes les instances de la fonction de rappel. Je pense que si vous appelez une fonction et passez la variable d'index à celle-ci et, en même temps, Étendre la variable de demande localement à la fonction utilisez le paramètre de réponse du gestionnaire done, vous devriez vous retrouver avec des variables indépendantes capturées par le rappel. Il devrait ensuite référencer correctement chaque élément du tableau et chaque variable de réponse.

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')]);
    });
}
20
tvanfosson

ressemble à votre i n'est pas correctement fermé

de plus, vous ne pouvez pas utiliser ajaxSizeRequest car elle aussi pointe vers une seule requête (probablement la dernière, car la boucle s'exécutera très rapidement)

enveloppez simplement votre fonction de rappel success comme suit, en changeant la référence en ajaxSizeRequest:

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

Vous pouvez voir que j'aime bien:

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

Si quelqu'un a encore des problèmes avec cela, et puisque ce message a déjà 5 ans, voici une version plus «moderne» de la réponse: utilisez simplement let au lieu de var dans la boucle for du message d'origine.

Info: Y a-t-il une raison d'utiliser le mot clé "var" dans ES6? et: MDN - Soit la syntaxe

0
Coffee

Vous avez une seule variable i qui est partagée par tous les rappels.
Étant donné que AJAX est asynchrone, tous les rappels sont exécutés une fois la boucle terminée, et ils reçoivent tous la même i.

Pour résoudre ce problème, vous devez déplacer l'appel AJAX dans une fonction distincte qui prend i en tant que paramètre.
Ainsi, chaque rappel recevra un paramètre i distinct.

0
SLaks