JavaScript로 이미지 미리로드


263

아래에 작성한 기능이 오늘날 일반적으로 사용되는 대부분의 브라우저에서 이미지를 미리로드하기에 충분합니까?

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

루프하고 preloadImage각 URL에 대한 함수를 호출하는 이미지 URL 배열이 있습니다.


19
일부 (전체?) 브라우저는 이미지를 사용하지 않은 경우 몇 초 후에 이미지를 해제합니다. 이를 피하려면 img개체에 대한 참조를 유지하십시오 ( 예 : 부모 범위의 배열).
Tamlyn

3
"이미지 릴리스"는 무엇을 의미합니까? 브라우저에서 캐시 한 경우 그대로 유지됩니다.
Francisc

56
조금 더 짧은 :(new Image()).src = url;
mrzmyr

20
크롬 devtool이 열려 있고 네트워크 패널 내에서 'chache 비활성화'가 활성화 된 경우에는 작동하지 않습니다
Wayou

6
더 짧은 :new Image().src = url;
Daniel X Moore

답변:


163

예. 모든 주요 브라우저에서 작동합니다.


48
중재자 참고 : "답이 아님"으로 표시를 중지하십시오. 사실 그것은 질문에 대한 직접적인 대답입니다. 답변이 잘못되었다고 생각되거나 증거가 충분하지 않다고 생각되면 답을 내리 십시오.
코디 그레이

43

이것을보십시오 나는 이것이 더 낫다고 생각합니다.

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
onload이미지에 대한 처리기 가 없습니다
Benny

12
이것이 더 좋은 이유를 설명해 주시겠습니까?
JJJ

2
@BeNice 당신이 오해하고 있다고 생각합니다. 이미지를로드하는 것은 비동기 적이므로 onload상태 를 처리해야 하거나 메모리에서 이미지를 인스턴스화하고 있습니다.
Benny

3
이 솔루션을 사용하는 경우 i- 변수에 대한 var 문을 잊지 마십시오. 그렇지 않으면 전역 적으로 설정되어 실제로 해결하기 어려운 오류가 발생할 수 있습니다 (var 문을 잊어 버린 경우를 제외하고for (var i = 0.....
Mohammer

2
@Mohammer 감사합니다. 방금 제공 한 링크에서 코드를 복사했습니다. 코드를 편집하여var
clintgh

26

필자의 경우 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');
});

19

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


고마워 mplungjan. 이 특별한 경우에는 도움이되지 않지만 알아 두는 것이 좋습니다.
Francisc

5
페이지가로드 이벤트를 시작하기 전에 이러한 이미지를 다운로드해야하기 때문에 이것이 페이지 로딩을 느리게 할 것이라고 말하고 있습니까?
jakubiszon

3
나는 이것이 모든 브라우저에서 작동한다고 생각하지 않습니다. Chrome에서 이미지가 보일 때까지로드되지 않는다는 것을 알고 있습니다. 디스플레이를 제거해야합니다. none; 대신 볼 수 없도록 위치를 조정하십시오. 필요한 경우 모든 것이로드 된 후 JS로 숨길 수 있습니다.
Bullyen

3
요소의 배경 이미지는 display: none사전로드되지 않습니다.
Marquizzo

1
이 방법은 I (1) 사용하지 않은 나를 위해 일한 display: none, (2)는 사용하지 않았다 width/height: 0, (3) 넣어 no-repeat및 위치 등의 이미지가 외부가 (될 것이라고 -<width>px -<height>px, 거기에 당신을 얻을 것이다 그래서 당신의 이미지가 모두 100 픽셀 경우 높이 이하, 당신은 사용할 수 있습니다 0 -100px즉, url(...) no-repeat 0 -100px.
알렉시스 WILKE

11

몇 가지 가능한 문제를 방지하기 위해 try / catch를 사용하는 것이 좋습니다.

죄송합니다 :

    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의 기여와 반대로 IMHO를 피하십시오. Image ()는 오래된 휴지통 브라우저에서 더 잘 지원됩니다.


7
나는 이것이 자바 스크립트에서 이미지를로드 할 때 오류를 잡는 방법이라고 생각하지 않습니다-_img.onerror와 같은 것이 사용될 수 있습니다.
Greg0ry

3
"가능한 문제"는 무엇입니까?
Kissaki

명령 지원과 같은 문제 지원해야하는 브라우저가 javascript 명령을 지원하는지 확인하려면 "사용할 수있는"사이트를 확인하십시오.
Dave

10

이 접근법은 조금 더 정교합니다. 여기에 미리로드 된 모든 이미지를 컨테이너에 저장합니다 .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;
}

여기에 시도해보십시오. 댓글도 추가했습니다.


7
const preloadImage = src => 
  new Promise(r => {
    const image = new Image()
    image.onload = r
    image.onerror = r
    image.src = src
  })


// Preload an image
await preloadImage('https://picsum.photos/100/100')

// Preload a bunch of images in parallel 
await Promise.all(images.map(x => preloadImage(x.src)))

5

예, 작동 하지만 브라우저는 제한됩니다 실제 호출 하므로 (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;
}

이 브라우저 한도에 대한 참조를 연결해 주시겠습니까?
nulll

참조를 찾기는 어렵지만 (적어도 하나도 찾지 못함) Chrome 개발자 도구 (f12)에서 Chrome의 네트워크 탭을 사용하여 캐시 및 서버 호출에서로드 된 내용을 자세히 보면서 내 프로젝트를 사용하여이를 테스트했습니다. Firefox와 모바일에서 동일한 동작을 발견했습니다.
Robin

1
-1 여기에서 첫 번째 문장의 주장을 신중하게 테스트하고 적어도 현대 브라우저에서는 허위 사실을 발견했기 때문입니다. stackoverflow.com/a/56012084/1709587을 참조하십시오. 예, 브라우저가 보내려는 최대 병렬 HTTP 요청 수에는 제한이 있지만 질문에 표시된 방식으로 수행하더라도 preloadImage를 호출하는 모든 URL을 요청하는 것으로 끝납니다.
Mark Amery 10

5

내 접근 방식은 다음과 같습니다.

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

4

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

또는 Promise.all병렬로로드하는 데 사용하십시오 .

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

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

약속에 대해 자세히 알아보십시오 .

"비동기"기능에 대한 추가 정보 .

구조 지정 할당에 대해 자세히 알아보십시오 .

ECMAScript 2015에 대해 자세히 알아보십시오 .

ECMAScript 2017에 대해 자세히 알아보십시오 .


2

질문에 대한 접근 방식으로 이미지가 다운로드 및 캐시되도록 트리거하기에 충분하다는 것을 확인할 수 있습니다.

  • 크롬 74
  • 사파리 12
  • Firefox 66
  • 가장자리 17

이를 테스트하기 위해 새끼 고양이의 그림을 제공하기 전에 각각 10 초 동안 잠자는 여러 끝 점이있는 작은 웹 응용 프로그램을 만들었습니다. 그런 다음 두 개의 웹 페이지를 추가했는데, 그 중 하나 에는 질문 <script>preloadImage기능을 사용하여 각 새끼 고양이가 미리로드되어 있고 다른 하나에는 <img>태그를 사용하여 페이지에 모든 새끼 고양이가 포함되어 있습니다.

위의 모든 브라우저에서 프리 로더 페이지를 먼저 방문한 후 잠시 기다렸다가 <img>태그 가있는 페이지로 이동하면 새끼 고양이가 즉시 렌더링됩니다. 이것은 프리 로더가 테스트 된 모든 브라우저에서 캐시에 새끼 고양이를 성공적으로로드했음을 보여줍니다.

https://github.com/ExplodingCabbage/preloadImage-test 에서 이것을 테스트하는 데 사용한 응용 프로그램을 보거나 시험해 볼 수 있습니다 .

특히이 기술은 반복되는 이미지 수가 브라우저가 한 번에 할 의사가있는 병렬 요청의 수를 초과하더라도 Robin의 답변이 제안 하는 것과는 달리 위의 브라우저에서 작동 합니다. 이미지 프리로드는 물론 얼마나 많은 병렬로 제한하는 비율은 브라우저 보낼 의향이 요청하지만 됩니다 결국 전화 각 이미지의 URL 요청 preloadImage()에 있습니다.


이미지가 메모리에 캐시되는지 디스크에 캐시되는지가 중요합니까? 메모리에 캐시되는 @clintgh 메서드와 달리 OP 메서드가 디스크에 캐시되는 것 같습니다.
Chris L

1

모든 URL에서 이미지를 미리로드하기 위해이 코드를 index.html로 이동할 수 있습니다.

<link rel="preload" href="https://via.placeholder.com/160" as="image">

0

브라우저는 헤드의 링크 태그를 사용하는 것이 가장 좋습니다.

export function preloadImages (imageSources: string[]): void {
  imageSources
    .forEach(i => {
      const linkEl = document.createElement('link');
      linkEl.setAttribute('rel', 'preload');
      linkEl.setAttribute('href', i);
      linkEl.setAttribute('as', 'image');
      document.head.appendChild(linkEl);
    });
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.