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

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

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

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

Ответ 1

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

Ответ 2

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

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/

Ответ 3

Альтернатива 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 не может быть предварительно загружен. Возможно видимость: скрытый будет работать лучше, но я не проверял это. Спасибо Marco Del Valle за указание на это

Ответ 4

В моем случае было полезно добавить обратный вызов в вашу функцию для события 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 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');
});

Ответ 5

Этот подход немного более сложный. Здесь вы сохраняете все предварительно загруженные изображения в контейнере, может быть 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;
}

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

Ответ 6

Я рекомендую использовать 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, поэтому вообще избегайте их ИМХО, вопреки тому, что он сказал. Image() имеет лучшую поддержку в старых браузерах корзины.

Ответ 7

Да, это будет работать, однако браузеры будут ограничить (между 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;
}

Ответ 8

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

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);
    }
};

Ответ 9

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

  • Chrome 74
  • Safari 12
  • Firefox 66
  • Край 17

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

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

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

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

Ответ 10

Решение для браузеров, совместимых с 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 image...");

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

    console.log("My cat image is ready! Now is the time to load my dog 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);
}

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

Подробнее о функциях "Async".

Подробнее о деструктурирующем задании.

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

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

Ответ 11

предварительно загрузите массив изображений в DOM в нижней части элемента body

function preloadImages(srcArray) {    
  for (var i = 0, len = srcArray.length; i < len; i++) {
      var img = new Image(); 
      img.src = srcArray[i];
      img.style.display = 'none';
      document.body.appendChild(img);
  }        
}

пример использования:

preloadImages([
  'public/img/img1.png',
  'public/img/img2.png'
  ]
)