I cannot find a proper solution to cancel openfl.display.Loader which has not yet started sending request (due to queue limited in HTML5HTTPRequest to 4x requests at once or anything) - I tried using method close() but it does not seem to work as I expected (under the hood it seems to run abort() method of HttpRequest). Am I doing something wrong or is there another way to overcome that.
My use case is a long list (~1500x) of elements rendering and lazyloading only visible part + some offsets (only 10x are visible, ~20x are prepared for smooth experience) and those 20x elements have Loaders with URLs attached to them - while scrolling these are loaded and unloaded depending on scroll position and while Iām scrolling through the whole list Loaders (and thus HttpRequest) are stuck in queue and are sent one by one (within 4x-at-once limit) even though some of them are not used anymore and should be canceled.
I think the first issue is that perhaps 4 is too low, and we should pick a higher request limit for the browser. Too many and we run into errors, but there might be a better value in the middle. Happy to consider other approaches to this?
The cancel method here in the backend is called when a Lime HTTPRequest is canceled. It looks like the code here will apply a cancel behavior if the request is active, but does not check if it is waiting in a queue.
Iāve also seen another topic about that limit so I guess Iāll try to propose something either for limiting or for canceling queued requests. Iād love to help a lot more than that but I seem to have no spare time
Maybe Iāve looked through URLLoader instead of Loader but for the first one Iāve seen that URLLoaderās close() looks like this (and I guessed similar rules apply to Loader):
public function close ():Void {
if (__httpRequest != null) {
__httpRequest.cancel ();
}
}
__httpRequest is _IHTTPRequest and in __prepareRequest() method it is actually an instance of HTTPRequest which for HTML5 has HTML5HTTPRequest as a backend. Then in HTTPRequest:
public function cancel ():Void {
#if !doc_gen
__backend.cancel ();
#end
}
and then in Backend:
public function cancel ():Void {
if (request != null) {
request.abort ();
}
}
So my approach would be to skip aborted requests in processQueue() before asserting type and using appropriate loading method, somewhere here:
private static function processQueue ():Void {
if (activeRequests < requestLimit && requestQueue.length > 0) {
activeRequests++;
var queueItem = requestQueue.pop ();
queueItem.instance
switch (queueItem.type) {
case IMAGE:
__loadImage (queueItem.uri, queueItem.promise);
case TEXT:
queueItem.instance.__loadText (queueItem.uri, queueItem.promise);
case BINARY:
queueItem.instance.__loadData (queueItem.uri, queueItem.promise);
default:
activeRequests--;
}
}
}
A little bit of feedback on these thoughts would be helpful. Iād love not to start doing something terribly wrong
Also, maybe you can give me a little bit of insight before I start digging on my own - why does every single request for image is firstly XHR request for URL, then PNG request for base64 encoded data instead of directly requesting for PNG ? It may be a concept I still do not understand about HTML5
OK. Found another issue Iāve got before but only with direct URLLoader usage and with Sound files (*.mp3) - whenever URL has attatched parameter to force cache invalidation (for.example/image/foobar.png:1234 -> that ā:1234ā at the end) URLLoader treats it as unrecognized format because the extension pattern in switchā¦case clause is āpng:1234ā instead of āpngā:
contentLoaderInfo.contentType = switch (extension) {
case "json": "application/json";
case "swf": "application/x-shockwave-flash";
case "jpg", "jpeg": "image/jpeg";
case "png": "image/png";
case "gif": "image/gif";
case "js": "application/javascript";
default: "application/x-www-form-urlencoded"; /*throw "Unrecognized file " + request.url;*/
}
Iāll try to make a fix for that but Iād love to ensure whether such solution was not a part of something else.
EDIT: Ah, I see that you check for ā?ā as query index instead but for library-related things.
This part loads image statically through the whole requestQueue so I cannot access request to mark it as canceled. In the commit message for this part it is said only that it is for permissions fix āFix permissions for simple image loads on HTML5ā (7049f279b709cb1f30e23416a91f1b94f6065d04) - could you explain a little bit more what is this shortcut about ? It would help a lot. Iād rather understand things first, then implement something around
Perhaps the Fix permissions for simple image loads on HTML5 has something to do with CORS. If you are correct that the code is falling back to an XHR request rather than a standard img.src = "image.png" load, perhaps thatās whatās going on here ā if we arenāt doing something special, we try and load that way (which I think is implemented in BitmapData). I think youāre right that canceling that will be more complicated. We can set that aside and focus on the others.
In cancel, I think it should remove the request from the queue, if it is on the queue, or it could occur in the queue processing to detect if it was canceled, but I think removing it from the queue directly may be the better approach.
If png:1234 is really what comes through, though, it definitely would make sense to improve that code for better performance
Let me sum up things and maybe organize them a little bit because Iāve made a little mess in here while I was working on these matters.
Extracting extension from example URL: for.example/image/foobar.png:1234 - Iāve found a solution - itās simple and I could post it tomorrow but Iāve just spoken to our sysadmin and he explained that using :1234 instead of just ?ts=1234 was because some squid proxies (like few years ago) were not caching any URL with ?. So this will be fixed on our side and I see that queryIndex is already implemented within openfl.display.Loader
After fixing 1) - for now only locally - Iāve achieved a much better performance - no more falling back to XHR on images and it speeded a lot - it is acceptable for now but can be improved more with canceling requests
Iāve spent some time today to check for stuff around HTML5HTTPRequest and found out that Images are requested differently than ex. binaries or strings - Images use HTML5HTTPRequest::loadImage directly and since it is static function it does not have an instance of HTML5HTTPRequest in QueueItem::instance while the other two use URLRequest which creates HTML5HTTPRequest so it is possible to access it from outside to actually cancel the request. Is that really related to CORS ? Both of these approaches use XMLHttpRequest in the end so guess it should be no difference but maybe Iām missing something important here.
About the canceling - I believe that just marking requests as canceled and removing them in HTML5HTTPRequest::processQueue would be better approach. Iād worry for concurrent modifications to occur whenever both processing and canceling access the same List to pop or remove request. I try to propose something tomorrow or maybe over the upcoming weekend
About requestLimit - Iāve searched through history of the repository as well as searched for any informations on what would be the best number of concurrent requests and Iāve found out that most of the modern browser allow up to 6 concurrent connections to the same host. Iāve tested it briefly today and had no problems with the limit set to 6 (Chrome 69). Also in the history of repository Iāve found that it was previously set to 6 (3a5ab4c472ā¦ - āAdd queue for HTML5 image loadingā) and then set down to 4 (d593685dcbā¦ - āThrottle HTML5 image loadingā) back in 03.2017.
I also wanted to know if I come up with some ideas for fixing different stuff, how do you want me to post it - shall I fork master and pull request or do you want me to create a branch within openfl/lime repositories or maybe I should create an issue so anyone who encounter similar issues will be able to find it - Iām not very experienced with working on github (Iāve forked and pullrequested Spritesheet once but in this case may be different). This will help me later on with other fixes
4.) Iām okay with that approach. I donāt think the queue is referenced from multiple threads, though, so Iām not sure if we need to worry too much
5.) Iām happy to try 6 again, I donāt remember why it was set lower
The easiest approach is to click the āEditā button on any file on the Github site, make your changes online, then save and you can turn that into a pull request. Even if it isnāt āperfectā I can still merge and make edits.
There are other ways to do it offline, but the online approach is the easiest for smaller changes
I understand now what have you meant by has something to do with CORS. Now, when I understand what you meant by that I can try refactoring HTML5HTTPRequest keeping it in compliance with that CORS requirement while having canceling possible from where request for an image was called. Iāve tried once and threw everything to trash. I guess it is harder than Iāve thought it may be but thatās OK Results soon, whenever I have some spare time to work on these things
if (!__isSameOrigin(uri)) {
image.crossOrigin = "Anonymous";
}
Iāve dumped some more changes to bin but every time I get some new knowledge about how things are working around there. It is harder than I thought it may be but coming soon