предварительно загрузить изображение с помощью ajax

Нашел этот метод использования ajax для предварительной загрузки по адресу: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

window.onload = function() {
    setTimeout(function() {
        // XHR to request a JS and a CSS
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://domain.tld/preload.js');
        xhr.send('');
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://domain.tld/preload.css');
        xhr.send('');
        // preload image
        new Image().src = "http://domain.tld/preload.png";
    }, 1000);
};

Я заметил, что предварительная загрузка «ajax» для этого изображения на самом деле совсем не ajax. Это то же самое, что я использовал уже много лет, просто устанавливая URL-адрес в источнике нового объекта изображения и позволяя браузеру загрузить его в кеш.

Теперь представьте, что есть приложение, в котором мне нужно фактически отменить предварительную загрузку изображения, если она занимает определенное время. На самом деле нет хорошего способа сделать это, просто установив изображение в src, в отличие от метода xhr.abort(), который останавливает загрузку фактического запроса xhr.

Есть ли какая-либо причина, по которой выполнение чего-либо, подобного приведенному ниже, не будет выполнять предварительную загрузку изображения и позволит отменить запрос на предварительную загрузку?

function preload(url, timeout){
    this.canceltimeout = function(){
        clearTimeout(this.timeout);
        this.loaded = true;
        return false;
    }

    this.abort = function(){
        this.xhr.abort();
        this.aborted = true;
    }

    //creates a closure to bind the functions to the right execution scope
    this.$_bind = function(method){
        var obj = this;
        return function (e){ obj[method](e);};
    }

    //set a default of 10 second timeout
    if(timeout == null){
        timeout = 10000;
    }

    this.aborted = false;
    this.loaded = false;
    this.xhr = new XMLHttpRequest();
    this.xhr.onreadystatechange = this.$_bind('canceltimeout');
    this.xhr.open('GET', url);
    this.xhr.send('');
    this.timeout = setTimeout(this.$_bind('abort'), timeout);
}

var llama = new preload('/image.gif');
show_image();

function show_image(){
    if(llama.loaded){
        var l = new Image();
        l.src = '/image.gif';
        application.appendChild(l);
    }else if(llama.aborted){
        var l = document.createElement('p');
        l.innerHTML = 'image.gif got cancelled';
        application.appendChild(l);
    }else{
        setTimeout(show_image, 10);
    }
    return false;
}

person Reid Johnson    schedule 01.06.2012    source источник
comment
используйте jquery man. api.jquery.com/jQuery.ajax   -  person Patrick Lorio    schedule 01.06.2012
comment
мог бы использовать jquery, но это действительно не имеет никакого отношения к тому, достаточно ли использования объекта xhr для запроса изображения, чтобы загрузить его в кеш. Jquery довольно громоздкий и действительно не помогает, когда вам нужна только небольшая его часть.   -  person Reid Johnson    schedule 01.06.2012
comment
Я вижу, что функция show_image, которую я опубликовал, немного тарабарщина. application — это глобальная переменная из какого-то другого javascript, к которому я добавил этот код, чтобы попробовать его. Казалось, это сработало, но у меня не так много разных браузеров или знаний об их кешах, чтобы посмотреть, будет ли это работать в кросс-браузерном режиме.   -  person Reid Johnson    schedule 01.06.2012
comment
Причина, по которой это может не работать, связана с междоменными политиками, кроме того, что это выглядит хорошо.   -  person Patrick Lorio    schedule 01.06.2012
comment
Не беспокойтесь о междоменных политиках, так как все изображения на сайте, где это рассматривалось, предоставляются непосредственно с нашего сервера, но даже если это не так, вы можете легко обойти это с помощью небольшой магии сценариев на стороне сервера, чтобы получить изображение и передать его обратно. если вызов был сделан скрипту на стороне сервера, а не изображению.   -  person Reid Johnson    schedule 01.06.2012


Ответы (1)


Основным недостатком является то, что если вы не настроили свой веб-сервер для предоставления информации о будущей свежести (заголовок http Expires или Cache-control: max-age, который будет в будущем), веб-браузер может сделать второй HTTP-запрос к серверу, когда вы установите image.src , или просто использовать изображение в документе. Если ваш веб-сервер отправил заголовки проверки свежести (last-modified или e-tag), то изображение не будет повторно загружено, но запрос на проверку актуальности все равно будет выполнен, что расточительно и увеличивает задержку в процессе.

Я не знаю почему, но браузеры очень любят кэшировать изображения, когда вы держите ссылку на объект Image().

Если вы посмотрите на сетевую панель в инструментах отладки веб-браузеров, вы увидите, что большинство браузеров делают первые 2 запроса, но не 3-й. Комментируя код в обратном вызове ajax, вы увидите запрос, сделанный для # 3

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
<script>
var f = "0.png?" + (new Date); // 0.png should not have future freshness info headers

$.get(f, function() {
    var i = new Image();
    i.src = f;
});
setTimeout(function(){
    //#3
    var i = new Image();
    i.src = f;
}, 5000);
</script>
person goat    schedule 01.06.2012
comment
На моем актуальном сервере изображения динамически изменяются в размерах и помечаются водяными знаками с помощью php-скрипта, поэтому было довольно легко дать им все правильные заголовки управления кешем. Чтобы сделать все это динамически, требуется немного дополнительного времени, но клиенты настолько невероятно обеспокоены тем, что кто-то украл их изображения, что предварительная загрузка плюс кеш на стороне сервера для измененных версий, которые я внедрил, кажется лучшим способом уменьшить задержку, вызванную весь этот процесс. Спасибо за понимание. - person Reid Johnson; 01.06.2012