JavaScript - Einstellung Eigenschaft auf Objekt in der Bildladefunktion, Eigenschaft nicht einmal außerhalb Funktion gesetzt
-
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.
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.