diff --git a/src/core/a-assets.js b/src/core/a-assets.js index 5fbb7dbc7a6..2ae53599346 100644 --- a/src/core/a-assets.js +++ b/src/core/a-assets.js @@ -57,18 +57,21 @@ class AAssets extends ANode { for (i = 0; i < imgEls.length; i++) { imgEl = fixUpMediaElement(imgEls[i]); loaded.push(new Promise(function (resolve, reject) { + // Bind the current img to a local so onload below does not close + // over the shared outer loop variable. + var el = imgEl; // Set in cache because we won't be needing to call three.js loader if we have. // a loaded media element. - if (imgEl.complete) { - THREE.Cache.add('image:' + imgEls[i].getAttribute('src'), imgEl); + if (el.complete) { + THREE.Cache.add('image:' + el.getAttribute('src'), el); resolve(); return; } - imgEl.onload = function () { - THREE.Cache.add('image:' + imgEls[i].getAttribute('src'), imgEl); + el.onload = function () { + THREE.Cache.add('image:' + el.getAttribute('src'), el); resolve(); }; - imgEl.onerror = reject; + el.onerror = reject; })); } diff --git a/tests/core/a-assets.test.js b/tests/core/a-assets.test.js index b3f11b23cc0..f90176f9b55 100644 --- a/tests/core/a-assets.test.js +++ b/tests/core/a-assets.test.js @@ -88,6 +88,34 @@ suite('a-assets', function () { document.body.appendChild(sceneEl); }); + test('caches image loaded asynchronously alongside media element', function (done) { + var assetsEl = this.el; + var sceneEl = this.scene; + + // Use a cache-busted src so the browser has to actually fetch, making + // imgEl.complete false when the Promise executor runs and forcing the + // onload path to be exercised. + var src = IMG_SRC + '?async-load-test'; + THREE.Cache.remove('image:' + src); + + var img = document.createElement('img'); + img.setAttribute('src', src); + assetsEl.appendChild(img); + + // A sibling media element ensures the image onload callback is + // verified alongside a non-trivial asset list. + var audio = document.createElement('audio'); + audio.setAttribute('src', ''); + assetsEl.appendChild(audio); + + sceneEl.addEventListener('loaded', function () { + assert.equal(THREE.Cache.get('image:' + src), img); + done(); + }); + + document.body.appendChild(sceneEl); + }); + test('does not wait for media element without preload attribute', function (done) { var el = this.el; var scene = this.scene;