当具有异步事件的另一个函数完成时运行函数

时间:2015-12-24 04:57:51

标签: javascript jquery asynchronous callback asynccallback

我正在研究一个动态画布动画,它将加载多个图像并为其设置动画。

似乎我遇到了竞争状态,我不知道如何解决它。

此对象构造函数加载图像,为它们创建对象,并将宽度和高度变量设置为自然图像大小的1/2。

window.imgWidth;
window.imgHeight;

//array to hold character objects
window.character = [];
window.characterPosition;

function Character(name, x, y){
    //define the image object within the Character
    this.imageObject = new Image();
    this.imageObject.src = 'data:text/javascript;base64,'+name;

    window.character.push(this);
    window.characterPosition = window.character.indexOf(this);

    //set natural width and natural height once the image is loaded
    //conditional used by Chrome
    if (this.imageObject.addEventListener){
        this.imageObject.addEventListener('load', function(){
            window.imgWidth = this.naturalWidth/2;
            window.imgHeight = this.naturalHeight/2;

            //set natural width and natural height to object
            window.character[characterPosition]['imageObject']['w'] = window.character[characterPosition]['imageObject']['w0'] = window.imgWidth;
            window.character[characterPosition]['imageObject']['h'] = window.character[characterPosition]['imageObject']['h0'] = window.imgHeight;

            //set initial x and y position
            window.character[characterPosition]['imageObject']['x1'] = x;
            window.character[characterPosition]['imageObject']['y1'] = y;

            //set loaded property for the object once loading is done
            window.character[characterPosition]['imageObject']['loaded'] = true;

            console.log(characterPosition);
            console.log(window.character[characterPosition]['imageObject']);

            function imageLoaded(element, index, array){
                return element['imageObject']['loaded'] == true;
            }

            //test whether every object in array has the image loaded
            if(character.every(imageLoaded)){
                $('button#play').show();
            };
        });
    }
} //end object constructor

准备好内部文档,我正在使用此对象构造函数创建两个对象。

var sun0 = new Character('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAW0lEQVR42mL8//8/AzpgZGTcC6KBcs5wMRwK/0MVMsLEmLAoEmXAApiwiKUhaRJCltgLsQVsWwIQ/wTx0fBeRigD7B6Y24i1mj4Kn4KI7Uie2Y7FI8+B2AMgwABjRynfWgpcxQAAAABJRU5ErkJggg==', 12, 12);
var sun1 = new Character('R0lGODlhCgAKANUCAEKtP0StQf8AAG2/a97w3qbYpd/x3mu/aajZp/b79vT69MnnyK7crXTDcqraqcfmxtLr0VG0T0ivRpbRlF24Wr7jveHy4Pv9+53UnPn8+cjnx4LIgNfu1v///37HfKfZpq/crmG6XgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAKAAoAAAZIQIGAUDgMEASh4BEANAGAxRAaaHoYAAPCCZUoOIDPAdCAQhIRgJGiAG0uE+igAMB0MhYoAFmtJEJcBgILVU8BGkpEAwMOggJBADs=',0,0);

问题是,由于this.imageObject.addEventListener('load', function(){是异步的,每次运行对象构造函数时运行的console.log消息都显示来自第二个对象的信息。我希望第一组显示来自第一个对象的信息,第二组显示来自第二个对象的信息。

//First set, run by sun0
  console.log(characterPosition); //1
  console.log(window.character[characterPosition]['imageObject']); //info for sun1
//Second set, run by sun1
  console.log(characterPosition); //1
  console.log(window.character[characterPosition]['imageObject']); //info for sun1

JS Fiddle demonstrating this

我能够通过设置这样的计时器来解决它:

var sun0 = new Character('iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAW0lEQVR42mL8//8/AzpgZGTcC6KBcs5wMRwK/0MVMsLEmLAoEmXAApiwiKUhaRJCltgLsQVsWwIQ/wTx0fBeRigD7B6Y24i1mj4Kn4KI7Uie2Y7FI8+B2AMgwABjRynfWgpcxQAAAABJRU5ErkJggg==', 12, 12);
window.setTimeout(slowLoad, 2000);
function slowLoad(){
    var sun1 = new Character('R0lGODlhCgAKANUCAEKtP0StQf8AAG2/a97w3qbYpd/x3mu/aajZp/b79vT69MnnyK7crXTDcqraqcfmxtLr0VG0T0ivRpbRlF24Wr7jveHy4Pv9+53UnPn8+cjnx4LIgNfu1v///37HfKfZpq/crmG6XgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAIALAAAAAAKAAoAAAZIQIGAUDgMEASh4BEANAGAxRAaaHoYAAPCCZUoOIDPAdCAQhIRgJGiAG0uE+igAMB0MhYoAFmtJEJcBgILVU8BGkpEAwMOggJBADs=',0,0);
}

这按预期工作。

//First set, run by sun0
      console.log(characterPosition); //0
      console.log(window.character[characterPosition]['imageObject']); //info for sun0
//Second set, run by sun1
      console.log(characterPosition); //1
      console.log(window.character[characterPosition]['imageObject']); //info for sun1

JS Fiddle for this approach

但显然,我不想引入手动延迟,以便在sun0完成后才能使sun1的功能运行。如何在sun0完成其功能(包括异步部分)后立即运行var sun1?请记住,我将为几个(约15个)其他图像执行此操作。

1 个答案:

答案 0 :(得分:0)

可能有更好的方法,但是我用一个函数来解决这个问题,该函数中包含一堆条件语句,以便在运行创建该对象的函数之前查看是否定义了一个对象。

function loadImages(){
    if (!character[0]){
        var sun0 = new Character('sun0', sunParent.x, sunParent.y);
    } else if (!character[1]){
        var sun1 = new Character('sun1', sunParent.x, sunParent.y);
    } else if (!character[2]){
        var sun2 = new Character('sun2', sunParent.x, sunParent.y);
    } else if (!character[3]){
        var bed = new Character('bed', 50, 500);
    } else if (!character[4]){
        var bed = new Character('plant1', 480, 490);
    } else if(character.every(imageLoaded)){
        $('button#play').show();
    }

    //test whether every object in array has the image loaded
    function imageLoaded(element, index, array){
        return element['imageObject']['loaded'] == true;
    }
}

我最初在文档就绪时调用loadImages();,并在加载图像的异步部分内的结尾处调用它。

查看full file on github