-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Fix handling image/file cache for three r178 and above #5776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -173,13 +173,16 @@ suite('material', function () { | |
| var textureLoaderSpy = this.sinon.spy(THREE.TextureLoader.prototype, 'load'); | ||
| img.setAttribute('src', IMG_SRC); | ||
| img.setAttribute('id', 'foo'); | ||
| THREE.Cache.files[IMG_SRC] = img; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that setting the cache in the test was wrong in my opinion, that didn't test that we set the cache for img added in a-assets. I added a comment in the changes. |
||
| THREE.Cache.clear(); | ||
| assetsEl.appendChild(img); | ||
| el.sceneEl.appendChild(assetsEl); | ||
| // Adding the asset will add image:${IMG_SRC} in THREE.Cache.files | ||
| // without going through THREE.ImageLoader | ||
| el.addEventListener('materialtextureloaded', function () { | ||
| assert.notOk(imageLoaderSpy.called); | ||
| assert.notOk(textureLoaderSpy.called); | ||
| delete THREE.Cache.files[IMG_SRC]; | ||
| assert.ok(`image:${IMG_SRC}` in THREE.Cache.files); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: we should probably avoid directly inspecting
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done in #5778 |
||
| THREE.Cache.clear(); | ||
| THREE.ImageLoader.prototype.load.restore(); | ||
| THREE.TextureLoader.prototype.load.restore(); | ||
| done(); | ||
|
|
@@ -191,10 +194,11 @@ suite('material', function () { | |
| var imageLoaderSpy = this.sinon.spy(THREE.ImageLoader.prototype, 'load'); | ||
| el.addEventListener('materialtextureloaded', function () { | ||
| assert.ok(imageLoaderSpy.called); | ||
| assert.ok(IMG_SRC in THREE.Cache.files); | ||
| assert.ok(`image:${IMG_SRC}` in THREE.Cache.files); | ||
| THREE.ImageLoader.prototype.load.restore(); | ||
| done(); | ||
| }); | ||
| // The image is loaded via the material system using THREE.ImageLoader | ||
| el.setAttribute('material', 'src', IMG_SRC); | ||
| }); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The image element should only be added to the Cache in case the
completeflag is true. Otherwise, there's the possible (albeit unlikely) scenario that theImageLoaderencounters it while still incomplete, which would cause it to wait in an incompatible way, never resolving.This would require the asset loading timeout to be hit, but it's precisely this scenario that might benefit from a cache-miss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to produce this case with a modified examples/boilerplate/panorama/index.html
the example is bit silly because in a real case you would have used
but this second snippet won't go in ImageLoader, only the first one.
First the timeout feature is currently not quite working for images probably since 0d97218 because we're waiting for readyState complete (meaning DOM, stylesheets and images are loaded), so we actually create the setTimeout for the timeout feature after we loaded all images, some a-asset-item may still be loading though so the timeout feature is not completely broken. So first fix is to wait for readyState interactive (dom loaded only) or complete only for a-assets.
and also showing the loading screen earlier in readyState interactive so we don't stare at a white page. I'll do a PR for that.
Then we can indeed hit the timeout, but even with the timeout, all components initialization wait for readyState complete so actually all images are downloaded before any ImageLoader.load call by a material component, so triggering the case of loading the same image in ImageLoader while the img in a-assets is still downloading is not possible from what I can tell.
Moving the Cache.add when img is complete like this
make the test fail because the callback materialtextureloaded is executed before the img onload, a simple setTimeout won't do, a setTimeout 10 is working but not great
but because it's not really an issue, I think we don't need that Cache.add change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was testing with Slow 4G in Chrome, so the image took 25s to load and the timeout was 3s here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR to show the loading screen before downloading the images #5779
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for diving into this. It seems that images will indeed be complete due to the
readyStatecheck. That said there are still two scenarios that could trigger it:loading="lazy"attribute on images in<a-assets><a-scene>after the document has long loaded (e.g. loading the markup from a server and using something likecontainerEl.innerHTML = "<a-scene>....</a-scene>")Arguably both are quite rare and unlikely, though people sometimes do use A-Frame in ways that the
<a-scene>is only added into the document after page load (either on purpose or due to a JS framework).I've reproduced the test case failure, and what's happening is akin to the second scenario I described above. The document is already in the "complete" readyState when the
a-assetsandimgelements are created. But this just reveals that the test itself is flawed, the presence of the image in the cache is non-consequential to the rest of the test. Regardless when/if the image element is added to the cache, thematerialtextureloadedevent will take place before the imageonload, meaningimg.complete === false. If someone would do this in their scene, it would result in the following warning (until the image is loaded):Despite being unlikely I do still think we should only add it to the Cache once the image is
complete. Even if it wouldn't cause any harm now, it could become a very annoying bug down the line.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I did aa4db04 as part of #5778 I'll rename the title of that PR.