Предварительная загрузка изображений с помощью JavaScript - PullRequest
200 голосов
/ 05 сентября 2010

Достаточно ли написанной ниже функции для предварительной загрузки изображений в большинстве, если не во всех браузерах, обычно используемых сегодня?

function preloadImage(url)
{
    var img=new Image();
    img.src=url;
}

У меня есть массив URL-адресов изображений, которые я зацикливаю и вызываю preloadImage функция для каждого URL.

Ответы [ 10 ]

109 голосов
/ 05 сентября 2010

Да. Это должно работать во всех основных браузерах.

37 голосов
/ 30 марта 2015

Попробуйте, я думаю, что это лучше.

var images = [];
function preload() {
    for (var i = 0; i < arguments.length; i++) {
        images[i] = new Image();
        images[i].src = preload.arguments[i];
    }
}

//-- usage --//
preload(
    "http://domain.tld/gallery/image-001.jpg",
    "http://domain.tld/gallery/image-002.jpg",
    "http://domain.tld/gallery/image-003.jpg"
)

Источник: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

18 голосов
/ 05 сентября 2010

CSS2 Альтернатива: http://www.thecssninja.com/css/even-better-image-preloading-with-css2

body:after {
  content: url(img01.jpg) url(img02.jpg) url(img03.jpg);
  display: none; 
}

CSS3 Альтернатива: https://perishablepress.com/preload-images-css3/ (H / T Linh Dam)

.preload-images {
  display: none; 
  width: 0;
  height: 0;
  background: url(img01.jpg),
              url(img02.jpg),
              url(img03.jpg);
}

ПРИМЕЧАНИЕ. Изображения в контейнере с display:none могут не загружаться предварительно. Возможно видимость: скрытый будет работать лучше, но я не проверял это. Спасибо Марко Дель Валле за то, что указал на это

16 голосов
/ 05 июля 2016

В моем случае было полезно добавить обратный вызов для вашей функции для события onload:

function preloadImage(url, callback)
{
    var img=new Image();
    img.src=url;
    img.onload = callback;
}

А затем обернуть его для случая массива URL-адресов к изображениям, которые должны быть предварительно загружены с обратным вызовом для всех: https://jsfiddle.net/4r0Luoy7/

function preloadImages(urls, allImagesLoadedCallback){
    var loadedCounter = 0;
  var toBeLoadedNumber = urls.length;
  urls.forEach(function(url){
    preloadImage(url, function(){
        loadedCounter++;
            console.log('Number of loaded images: ' + loadedCounter);
      if(loadedCounter == toBeLoadedNumber){
        allImagesLoadedCallback();
      }
    });
  });
  function preloadImage(url, anImageLoadedCallback){
      var img = new Image();
      img.onload = anImageLoadedCallback;
      img.src = url;
  }
}

// Let's call it:
preloadImages([
    '//upload.wikimedia.org/wikipedia/commons/d/da/Internet2.jpg',
  '//www.csee.umbc.edu/wp-content/uploads/2011/08/www.jpg'
], function(){
    console.log('All images were loaded');
});
10 голосов
/ 13 сентября 2013

Я рекомендую вам использовать try / catch, чтобы предотвратить некоторые возможные проблемы:

OOP:

    var preloadImage = function (url) {
        try {
            var _img = new Image();
            _img.src = url;
        } catch (e) { }
    }

Стандарт:

    function preloadImage (url) {
        try {
            var _img = new Image();
            _img.src = url;
        } catch (e) { }
    }

Кроме того, хотя я люблю DOM, старые глупые браузеры могут иметь проблемы с вами, используя DOM, поэтому избегайте этого в целом ИМХО вопреки вкладу freedev. Функция Image () лучше поддерживается в старых браузерах для мусора.

10 голосов
/ 24 января 2013

Этот подход немного сложнее. Здесь вы храните все предварительно загруженные изображения в контейнере, может быть div. И после того, как вы сможете показать изображения или переместить их в DOM в правильное положение.

function preloadImg(containerId, imgUrl, imageId) {
    var i = document.createElement('img'); // or new Image()
    i.id = imageId;
    i.onload = function() {
         var container = document.getElementById(containerId);
         container.appendChild(this);
    };
    i.src = imgUrl;
}

Попробуйте здесь , я также добавил несколько комментариев

5 голосов
/ 13 мая 2016

Да, это будет работать, однако браузеры будут ограничивать (между 4-8) фактическими вызовами и, следовательно, не кэшировать / предварительно загружать все нужные изображения.

Лучший способ сделать это - вызвать onload перед использованием изображения следующим образом:

function (imageUrls, index) {  
    var img = new Image();

    img.onload = function () {
        console.log('isCached: ' + isCached(imageUrls[index]));
        *DoSomething..*

    img.src = imageUrls[index]
}

function isCached(imgUrl) {
    var img = new Image();
    img.src = imgUrl;
    return img.complete || (img .width + img .height) > 0;
}
4 голосов
/ 15 декабря 2016

Вот мой подход:

var preloadImages = function (srcs, imgs, callback) {
    var img;
    var remaining = srcs.length;
    for (var i = 0; i < srcs.length; i++) {
        img = new Image;
        img.onload = function () {
            --remaining;
            if (remaining <= 0) {
                callback();
            }
        };
        img.src = srcs[i];
        imgs.push(img);
    }
};
0 голосов
/ 08 мая 2019

Решение для браузеров, совместимых с ECMAScript 2017

Примечание: это также будет работать, если вы используете транспортер, такой как Babel.

'use strict';

function imageLoaded(src, alt = '') {
    return new Promise(function(resolve) {
        const image = document.createElement('img');

        image.setAttribute('alt', alt);
        image.setAttribute('src', src);

        image.addEventListener('load', function() {
            resolve(image);
        });
    });
}

async function runExample() {
    console.log("Fetching my cat's image...");

    const myCat = await imageLoaded('https://placekitten.com/500');

    console.log("My cat's image is ready! Now is the time to load my dog's image...");

    const myDog = await imageLoaded('https://placedog.net/500');

    console.log('Whoa! This is now the time to enable my galery.');

    document.body.appendChild(myCat);
    document.body.appendChild(myDog);
}

runExample();

Вы также могли дождаться загрузки всех изображений наодин раз.

async function runExample() {
    const [myCat, myDog] = [
        await imageLoaded('https://placekitten.com/500'),
        await imageLoaded('https://placedog.net/500')
    ];

    document.body.appendChild(myCat);
    document.body.appendChild(myDog);
}

Подробнее об обещаниях .

Подробнее о функциях "Асинхронизация" .

Подробнеео задании по деструктуризации .

Подробнее об ECMAScript 2015 .

Подробнее об ECMAScript 2017 .

0 голосов
/ 06 мая 2019

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

  • Chrome 74
  • Safari 12
  • Firefox 66
  • Edge 17

Чтобы проверить это, я создал небольшое веб-приложение с несколькими конечными точками, котороекаждый спит по 10 секунд перед тем, как подать фотографию котенка.Затем я добавил две веб-страницы, одна из которых содержала тег <script>, в котором каждый из котят предварительно загружен с помощью функции preloadImage из вопроса, а другой , который включает в себя всех котят настраница с использованием тегов <img>.

Во всех браузерах, указанных выше, я обнаружил, что если я сначала зашел на страницу предварительного загрузчика, подождал некоторое время, а затем перешел на страницу с тегами <img>, мои котята отрисовалисьмгновенно.Это демонстрирует, что предварительный загрузчик успешно загрузил котят в кеш во всех протестированных браузерах.

Вы можете увидеть или опробовать приложение, которое я использовал для проверки этого на https://github.com/ExplodingCabbage/preloadImage-test.

Обратите внимание, в частности, чтоэта методика работает в вышеупомянутых браузерах, даже если количество зацикленных изображений превышает количество параллельных запросов, которые браузер готов сделать за один раз, вопреки тому, что ответ Робина предлагает.Скорость предварительной загрузки изображений, конечно, будет ограничена количеством параллельных запросов, которые браузер желает отправить, но в конечном итоге будет запрашивать каждый URL-адрес изображения, на который вы звоните preloadImage().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...