JavaScript - Einstellung Eigenschaft auf Objekt in der Bildladefunktion, Eigenschaft nicht einmal außerhalb Funktion gesetzt

StackOverflow https://stackoverflow.com/questions/2798103

  •  04-10-2019
  •  | 
  •  

Frage

Manchmal ist JavaScript keinen Sinn für mich machen, sollten Sie den folgenden Code, der ein Foto-Mosaik auf Basis von x / y Kacheln erzeugt. Ich versuche, eine DONE-Eigenschaft auf true gesetzt, wenn jedes Mosaik Bild heruntergeladen wurde, aber es ist aus irgendeinem Grunde immer falsch, was mache ich falsch?

var tileData = [];

function generate()
{
    var image = new Image();
    image.onload = function()
    {
        // Build up the 'tileData' array with tile objects from this Image

        for (var i = 0; i < tileData.length; i++)
        {
            var tile = tileData[i];

            var tileImage = new Image();
            tileImage.onload = function()
            {
                // Do something with this tile Image
                tile.Done = true;
            };
            tileImage.src = tile.ImageUrl;
        }
    };
    image.src = 'Penguins.jpg';

    tryDisplayMosaic();
}

function tryDisplayMosaic()
{
    setTimeout(function()
    {
        for (var i = 0; i < tileData.length; i++)
        {
            var tile = tileData[i];

            if (!tile.Done)
            {
                tryDisplayMosaic();
                return;
            }
        }

        // If we get here then all the tiles have been downloaded
        alert('All images downloaded');
    }, 2000);
}

Jetzt aus irgendeinem Grunde die .Done Eigenschaft auf dem tile Objekt immer falsch ist, auch wenn es explizit auf true innerhalb tileImage.onload = function() gesetzt wird. Und ich kann Sie sicherstellen, dass diese Funktion aufgerufen werden kann, da ich einen Anruf alert() Inneren platziert haben. Gerade jetzt ist es nur innerhalb einer Endlosschleife stecken Aufruf tryDisplayMosaic() ständig.

Auch wenn ich eine Schleife legen kurz vor tryDisplayMosaic() genannt wird, und in dieser Schleife I Satz .Done = true, dann .Done Eigenschaft wahr ist und alert('All images downloaded'); wird aufgerufen.

War es hilfreich?

Lösung

Die Variable „Kachel“ in der oberen Schleife wird durch jeden der „onload“ Funktionen geteilt Sie erstellen; die gleiche einzige Variable, mit anderen Worten. Versuchen Sie dies, jeder seine eigene Variable zu geben:

tileImage.onload = (function(myTile) {
  return function()
        {
            // Do something with this tile Image
            myTile.Done = true;
        };
})(tile);

Warum ist das so? Denn im Gegensatz zu C oder Java, „Kachel“ innerhalb der Schleife deklarieren wie das tut nicht macht scoped es den Anweisungsblock des Schleifenkörpers. Das einzige, was Sie Spielraum in Javascript gibt eine Funktion Körper.

Andere Tipps

Was ich sehe, ist, dass Sie Verschlüsse innerhalb von Schleifen erstellen, die ein gemeinsames Fehler . Um dies zu vermeiden, könnten Sie eine allgemeinere Schließung, außerhalb der Schleife erzeugen, die kümmert sich um alle die Last Ereignisse und führt eine Funktion aus, nachdem alle Bilder geladen werden:

// This array must be filled somewhere...
var tileData = [];

var ImageLoader = function(){
    var numOfImages = 0;
    var numLoaded   = 0;
    var callBack    = function(){};

    function imageLoaded(){
        numLoaded++;
        if(numLoaded===numOfImages){
            // All images are loaded, now call the callback function
            callBack.call(this);
        }
    }

    function init(numberOfImages, fn){
        numOfImages = numberOfImages;
        callBack = fn;
    }

    return {
        imageLoaded: imageLoaded,
        init: init
    };
}();

function tryDisplayMosaic(){
    alert('All images downloaded');
}

function generate(){
    // (1) Set the number of images that are to be loaded and (all tiles + penguin)
    // (2) Set the function that must be called after all images are loaded
    ImageLoader.init(tileData.length+1, tryDisplayMosaic);

    // Load this Penguins image
    var image = new Image();
    image.src = 'Penguins.jpg';
    image.onload = ImageLoader.imageLoaded;

    // Go through each image and load it
    for (var i=0; i<tileData.length; i++) {
        image = new Image();
        image.src = tileData[i].ImageUrl;
        image.onload = ImageLoader.imageLoaded;
    }
}

Dieser Code ist völlig anders als der Code, aber es ist viel schöner in meiner Meinung nach. Es erfordert, dass Sie die Anzahl der Bilder einstellen, die Sie laden und eine Funktion benötigen, die nach dem alle Bilder geladen werden ausgeführt werden müssen.

Hinweis: Ich habe es nicht getestet, ich bin mir nicht sicher über dieses .call(this) Teil, vielleicht das Forum helfen könnte, wenn es nicht richtig ist

.

Ich habe meinen Code getestet und es funktioniert gut. Außerdem habe ich es verbessert, so dass Sie einen Zeiger auf das geladene Bild im Inneren des tileData Array speichern, finden Sie unter JSBin für ein funktionierendes Beispiel.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top