Why do browsers inefficiently make 2 requests here?

前端 未结 9 2183
-上瘾入骨i
-上瘾入骨i 2021-02-13 14:48

I noticed something odd regarding ajax and image loading. Suppose you have an image on the page, and ajax requests the same image - one would guess that ajax requests would hit

相关标签:
9条回答
  • 2021-02-13 15:40

    This "problem" could a be a CORS pre-flight test.

    I had noticed this in my applications awhile back, that the call to retrieve information from a single page application made the call twice. This only happens when you're accessing URLs on a different domain. In my case we have APIs we've built and use on a different server (a different domain) than that of the applications we build. I noticed that when I use a GET or POST in my application to these RESTFUL APIs the call appears to be made twice.

    What is happening is something called pre-flight (https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS), an initial request is made to the server to see if the ensuing call is allowed.

    Excerpt from MDN:

    Unlike simple requests, "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:

    1. It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
    2. It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
    0 讨论(0)
  • 2021-02-13 15:47

    The helpful folks at Mozilla gave some details as to why this happens. Apparently Firefox assumes an "anonymous" request could be different than normal, and for this reason it makes a second request and doesn't consider the cached value with different headers to be the same request.

    https://bugzilla.mozilla.org/show_bug.cgi?id=1075297

    0 讨论(0)
  • 2021-02-13 15:48

    I want JS-accessible image

    Have you tried to CSS using jQuery? It is pretty fun - you have full CRUD (Create, read, update, delete) CSS elements. For example do image resize on server side:

    $('#container').css('background', 'url(somepage.php?src=image_source.jpg'
        + '&w=' + $("#container").width() 
        + '&h=' + $("#container").height() + '&zc=1');
    

    Surprisingly, I found that even when the javascript waits for the entire page to load, the image request still makes a new request! Is this a known bug in Firefox and Chrome, or something bad jQuery ajax is doing?

    It is blatantly obvious that this is not a browser bug.

    The computer is deterministic and does what exactly you tell it to (not want you want it to do). If you want to cache images it is done in server side. Based on who handles caching it can be handled as:

    1. Server (like IIS or Apache) cache - typically caches things that are reused often (ex: 2ce in 5 seconds)
    2. Server side application cache - typically it reuses server custom cache or you create sprite images or ...
    3. Browser cache - Server side adds cache headers to images and browsers maintain cache

    If it is not clear then I would like to make it clear : You don't cache images with javascript.

    Ideally I would hope the ajax wouldn't make a second request at all, since it is requesting exactly the same url.

    What you try to do is to preload images.

    Once an image has been loaded in any way into the browser, it will be in the browser cache and will load much faster the next time it is used whether that use is in the current page or in any other page as long as the image is used before it expires from the browser cache.

    So, to precache images, all you have to do is load them into the browser. If you want to precache a bunch of images, it's probably best to do it with javascript as it generally won't hold up the page load when done from javascript. You can do that like this:

    function preloadImages(array) {
        if (!preloadImages.list) {
            preloadImages.list = [];
        }
        for (var i = 0; i < array.length; i++) {
            var img = new Image();
            img.onload = function() {
                var index = preloadImages.list.indexOf(this);
                if (index !== -1) {
                    // remove this one from the array once it's loaded
                    // for memory consumption reasons
                    preloadImages.splice(index, 1);
                }
            }
            preloadImages.list.push(img);
            img.src = array[i];
        }
    }
    
    preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"]);
    

    Then, once they've been preloaded like this via javascript, the browser will have them in its cache and you can just refer to the normal URLs in other places (in your web pages) and the browser will fetch that URL from its cache rather than over the network.

    Source : How do you cache an image in Javascript

    Is there a reason css and ajax in this case usually have different caches, as though the browser is using different cache storage for css vs ajax requests?

    enter image description here

    Even in absence of information do not jump to conclusions!

    One big reason to use image preloading is if you want to use an image for the background-image of an element on a mouseOver or :hover event. If you only apply that background-image in the CSS for the :hover state, that image will not load until the first :hover event and thus there will be a short annoying delay between the mouse going over that area and the image actually showing up.

    Technique #1 Load the image on the element's regular state, only shift it away with background position. Then move the background

    position to display it on hover.

    #grass { background: url(images/grass.png) no-repeat -9999px -9999px; }
    #grass:hover { background-position: bottom left; }
    

    Technique #2 If the element in question already has a background-image applied and you need to change that image, the above

    won't work. Typically you would go for a sprite here (a combined background image) and just shift the background position. But if that isn't possible, try this. Apply the background image to another page element that is already in use, but doesn't have a background image.

    #random-unsuspecting-element { 
        background: url(images/grass.png) no-repeat -9999px -9999px; }
    #grass:hover { background: url(images/grass.png) no-repeat; }
    

    The idea create new page elements to use for this preloading technique may pop into your head, like #preload-001, #preload-002, but that's rather against the spirit of web standards. Hence the using of page elements that already exist on your page.

    0 讨论(0)
提交回复
热议问题