JavaScript-图像加载功能中的对象上设置属性,属性未设置一次外部功能

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

  •  04-10-2019
  •  | 
  •  

有时,JavaScript对我没有意义,请考虑以下代码,该代码基于X/Y瓷砖生成照片。下载每个马赛克图像后,我试图将.done属性设置为True,但是由于某种原因,这总是错误的,我在做什么错?

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

现在出于某种原因 .Donetile 即使对象明确将其设置为true内部 tileImage.onload = function(). 。我可以确保您确实被调用,因为我已经放置了 alert() 在里面打电话。现在,它只是卡在无限循环中 tryDisplayMosaic() 不断地。

另外,如果我在之前放置循环 tryDisplayMosaic() 被称为,在那个循环中我设置 .Done = true, , 然后 .Done 财产为真, alert('All images downloaded'); 会被打电话。

有帮助吗?

解决方案

顶部循环中的变量“瓷砖”都由您创建的每个“ Onload”函数共享;换句话说,相同的单个变量。尝试一下,给每个人自己的变量:

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

为什么这样?因为与C或Java不同,请在循环中宣布“瓷砖”。 不是 使其范围范围内的循环主体的声明块。唯一在JavaScript中为您提供范围的是功能主体。

其他提示

我看到的是您在循环内部创建关闭,这就是 一个普遍的错误. 。为了避免这种情况,您可以在循环外部创建一个更一般的封闭,该循环外部处理所有负载事件并在加载所有图像后执行功能:

// 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;
    }
}

该代码与您的代码完全不同,但在我看来,它更漂亮。它要求您设置需要加载的图像数量,并在加载所有图像后必须执行的函数。

注意:我没有测试,我不确定 .call(this) 部分,如果论坛不正确,该论坛可能会有所帮助。

我已经测试了我的代码,它可以正常工作。此外,我已经对其进行了改进 tileData 数组,看 Jsbin 对于工作示例。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top