web-dev-qa-db-fra.com

Comment annuler une image <img> en chargeant des requêtes sans utiliser window.stop ()

J'ai une très longue page qui charge dynamiquement les images lorsque les utilisateurs défilent.

Toutefois, si un utilisateur quitte rapidement une certaine partie de la page, je ne souhaite pas que les images continuent à être chargées dans cette partie de la page qui est maintenant masquée.

Outre le chargement d'images, de nombreuses autres requêtes se produisent simultanément sur la page. Par conséquent, un déclenchement brus de window.stop () sur l'événement de défilement n'est pas acceptable.

J'ai essayé de supprimer et d'effacer les attributs img src pour les images qui ne sont plus visibles, mais, comme la demande avait déjà été lancée, le chargement de l'image se poursuit.

Rappelez-vous que l'image src a été remplie lorsque l'utilisateur a fait défiler brièvement cette partie de la page. Une fois passée, je ne pouvais pas obtenir cette image en arrêtant le chargement sans utiliser window.stop (). Clearing src n'a pas fonctionné. (Chrome et FF)

Des articles similaires que j'ai trouvés se rapprochent, mais ne semblent pas résoudre ce problème:

43
Evan

Ce que vous essayez de faire est la mauvaise approche, comme mentionné par nrabinowitz . Vous ne pouvez pas simplement "annuler" le processus de chargement d'une image (définir l'attribut src sur une chaîne vide est ce n'est pas une bonne idée ). En fait, même si vous le pouviez, cela ne ferait qu'empirer les choses, car votre serveur enverrait continuellement des données qui seraient annulées, ce qui augmenterait son facteur de charge et le ralentirait. Aussi, considérez ceci:

  1. si votre utilisateur fait défiler frénétiquement la page, il s’attendra à des délais de chargement.
  2. avoir un délai d'attente (ex: 200 ms) avant de commencer à charger une partie de la page est assez acceptable, et combien de fois un arrêt et saut après 200 ms d'intervalle sur votre page? Même si ça arrive, ça revient au point 1
  3. quelle est la taille de vos images? Même un serveur lent peut servir environ quelques dizaines de milliards de milliards de clés par seconde. Si votre site contient de plus grandes images, utilisez des images de résolution basse et haute avec des composants tels que lightBox

Souvent, les problèmes informatiques sont simplement des problèmes de conception.

** MODIFIER **

Voici une idée:

  1. votre page doit afficher les conteneurs DIV avec la largeur et la hauteur de la taille d'image attendue (utilisez CSS pour styler). À l'intérieur de chaque DIV, ajoutez un lien. Par exemple :

    <div class="img-wrapper thumbnail">
       <a href="http://www.domain.com/path/to/image">Loading...</a>
    </div>
    
  2. Ajouter ce code Javascript (non testé, l'idée est auto-descriptive)

    $(function() {
    
    var imgStack;
    var loadTimeout;
    
    $(window).scroll(function() {
       imgStack = null;
       if (loadTimeout) clearTimeout(loadTimeout);
    
       loadTimeout = setTimeout(function() {
    
          // get all links visible in the view port
          // should be an array or jQuery object
          imgStack = ...
    
          loadNextImage();
       }, 200);                // 200 ms delay
    });
    
    function loadNextImage() {
       if (imgStack && imgStack.length) {
          var nextLink = $(imgStack.pop());   // get next image element
    
          $('<img />').attr('src', nextLink.attr('href'))
            .appendTo(nextLink.parent())
            .load(function() {
               loadNextImage();
            });
    
          // remove link from container (so we don't precess it twice)
          nextLink.remove();
       }
    };
    
    });
    
17
Yanick Rochon

Eh bien, mon idée:

1) lancer une demande AJAX pour l'image; si l'opération aboutit, l'image est placée dans la mémoire cache du navigateur, et une fois que vous avez défini l'attribut 'src', l'image est affichée à partir du cache

2) vous pouvez abandonner le XHR

J'ai écrit un petit serveur avec express imitant l'énorme téléchargement d'images (il attend 20 secondes, puis renvoie une image). Ensuite, j'ai ceci dans mon HTML:

<!DOCTYPE html>
<html>
    <head>
        <style>
            img {
                width: 469px;
                height: 428px;
                background-color: #CCC;
                border: 1px solid #999;
            }
        </style>
    </head>

    <body>
        <img data-src="./img" src="" />
        <br />
        <a id="cancel" href="javascript:void(0)">CANCEL</a>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(function () {
                var xhr, img = $('img'), src = img.data('src');

                xhr = $.ajax(src, {
                    success: function (data) { img.attr('src', src) }
                });

                $('#cancel').click(function (){
                    xhr.abort();
                })
            });
        </script>
    </body>
</html>
12
Guard

Vous pouvez charger vos images à l’aide d’appels ajax et, au cas où l’utilisation se déroulerait, vous pouvez abandonner les appels.
Dans le pseudo-code jQuery, ce serait quelque chose comme ça (pardonnez-moi les erreurs de syntaxe, ce n'est qu'un exemple):

1) taguer les images que vous voulez charger

$(".image").each( function(){
    if ( is_in_visible_area(this) ) { // check [1] for example
        $(this).addClass("load_me");
    } else {
        $(this).addClass("dont_load");
    }
});

2) charger des images

ajax_requests = {};

$(".image.load_me").each( function(){
    // load image
    var a = $.ajax({
        url: 'give_me_photos.php',
        data: {img: photo_id},
        success: function(html){
            photo_by_id(photo_id), img.append(html);
        }
    });
    ajax_requests[photo_id] = a;

});

3) annuler le chargement de ceux-ci hors de l'écran

for( id in ajax_requests ) {
    if ( ! is_in_visible_area(id) ) {
        ajax_requests[id].abort();
    }
}

Bien sûr, ajoutez aussi quelques vérifications si l’image est déjà chargée (par exemple la classe "chargée")

[1]. Vérifier si l'élément est visible après le défilement

[2] Abandonner les requêtes Ajax avec jQuery

2
Jakub M.
  1. Utilisez une pile pour gérer les requêtes ajax (cela signifie que vous aurez un chargement en série au lieu de parallèle mais cela en vaut la peine)

  2. À l’arrêt du défilement, attendez 300 ms, puis empilez toutes les images de la zone de vue

  3. Chaque fois qu'un utilisateur fait défiler, vérifiez si une pile est en cours d'exécution. (fyi - vous pouvez arrêter toutes les requêtes sur une URL particulière au lieu de tuer tous les appels ajax. Vous pouvez aussi utiliser regex pour ne pas arrêter les autres requêtes sur la page.)

  4. Si une pile existante est en cours d'exécution, affichez toutes les images qui s'y trouvent, à l'exception de la première.

  5. Sur tous les appels ajax - lie l'événement beforeSend () pour supprimer cette image particulière de la pile

Il est tard aujourd'hui, mais nous avons fait quelque chose de très similaire au travail - si vous avez besoin du code détaillé, faites-le-moi savoir.

À votre santé!

1
Varun Vohra

Peut-être que vous pourriez servir l'image via un script php qui vérifierait un champ de la base de données (ou mieux encore un memcached) qui indiquerait l'arrêt du chargement. le script divise l'image en fragments, fait une pause entre chaque morceau et vérifie si l'indicateur d'arrêt de la demande est bien défini. Si cette option est définie, l'en-tête n'est pas envoyé avec A 204, il ne contiendra plus de contenu dès que le navigateur l'aura reçu. 

Cela peut toutefois être un peu trop fatal.

0
matthewdaniel

BTW, une autre idée qui pourrait fonctionner:

1) créer un nouveau iframe

2) à l'intérieur de l'iframe, le script qui commence à charger l'image, puis une fois chargée, appelle la méthode .parent

3) en cas de besoin, arrêtez le chargement du contenu iframe à l’aide de .stop sur l’objet iframe

0
Guard

La solution pourrait être un webworker. un webworker peut être résilié et avec lui la connexion . Mais il y a un petit problème: le webworker utilise les connexions limitées du navigateur et l'application est bloquée.

En ce moment, je travaille sur une solution avec serviceWorkers - ils n'ont pas de limite de connexion (je l'espère)

0
teter