-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Make sure 204 image requests reject when using ImageBitmap #7914
Conversation
Thanks for the pull request @OmarShehata!
Reviewers, don't forget to make sure that:
|
@mramato I think you're most familiar with this code - would you like to review? Here is our previous conversation about this promise chain structuring: #7579 (comment) where you warned this type of issue might happen. Let me know what you think of my suggestion above. This is what the fix would look to keep the old promise chain style:
|
Thanks! |
This fixes #7906 (and most likely #7817 but the author didn't submit a reproducible example).
The issue was that
Resource._Implementations.createImage
was not rejecting the promise when it received an undefinedblob
(which happened when the request was 204, empty content). In fact, it was neither resolving not rejecting. This led to the imagery provider launching more and more requests for this image that gets neither resolved nor rejected, which starves out any other requests. So once you hit a single 204 request no new imagery would ever load.How to test this
Paste this code in Sandcastle in master:
Notice that once you add this layer, and move anywhere else on the globe, the default Bing layer never loads any new tiles (zoom in somewhere, it never loads a higher resolution).
In this branch, it should load fine, and the console should give you errors like
An error occurred in "UrlTemplateImageryProvider": Failed to obtain image tile X: 10 Y: 6 Level: 4.
which is correct.Why I refactored the promise chain
The fix is rather obvious, and I'm surprised we didn't catch it earlier. Below is what the
createImage
in master looks like. Notice theif (!defined(blob))
returning nothing, and not rejecting or resolving.The solution is simple right? Just throw a
deferred.reject
in that block. But this is incorrect. This promise chain is deceiving because you have to think about the two code-paths it's handling simultaneously when reasoning about it. There are 2 situations that causeblob
to be undefined:If
preferImageBitmap
is false or if it's just not supported, it loads the image usingloadImageElement
, which handles the promise resolving/rejecting, so the rest of the promise chain must not resolve/reject.We decided to use this pass-through style of chain to be more consistent with the rest of the code-base and it avoids nesting promises which are generally hard to follow - but in this case I think it causes more confusion. The real issue here I think is the mixing of the deferred pattern (since the old way of loading images isn't a promise) with ImageBitmap's API which is an actual promise.
I think what I have in this PR makes it more obvious what's happening, and would help avoid mistakes like this (in this case, even after I figured out the issue, I still solved it incorrectly and this was only caught because of the test I wrote).