使用 JavaScript 预加载图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3646036/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:34:12  来源:igfitidea点击:

Preloading images with JavaScript

javascript

提问by Francisc

Is the function I wrote below enough to preload images in most, if not all, browsers commonly used today?

我在下面编写的函数是否足以在当今常用的大多数(如果不是全部)浏览器中预加载图像?

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

I have an array of image URLs that I loop over and call the preloadImagefunction for each URL.

我有一组图像 URL,我循环遍历preloadImage这些 URL并为每个 URL调用函数。

采纳答案by Huzi--- Javiator

Yes. This should work on all major browsers.

是的。这应该适用于所有主要浏览器。

回答by clintgh

Try this I think this is better.

试试这个我觉得这个更好。

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"
)

Source: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

来源:http: //perishablepress.com/3-ways-preload-images-css-javascript-ajax/

回答by Alexander

In my case it was useful to add a callback to your function for onloadevent:

就我而言,为onload事件添加回调函数很有用:

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

And then wrap it for case of an array of URLs to images to be preloaded with callback on all is done: https://jsfiddle.net/4r0Luoy7/

然后将其包装为一组 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');
});

回答by mplungjan

CSS2 Alternative: http://www.thecssninja.com/css/even-better-image-preloading-with-css2

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 Alternative: https://perishablepress.com/preload-images-css3/(H/T Linh Dam)

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

NOTE: Images in a container with display:nonemight not preload. Perhaps visibility:hidden will work better but I have not tested this. Thanks Marco Del Valle for pointing this out

注意:容器中的图像display:none可能不会预加载。也许可见性:隐藏会更好,但我还没有测试过。感谢 Marco Del Valle 指出这一点

回答by Dave

I recommend you use a try/catch to prevent some possible issues:

我建议您使用 try/catch 来防止一些可能的问题:

OOP:

面向对象:

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

Standard:

标准:

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

Also, while I love DOM, old stupid browsers may have problems with you using DOM, so avoid it altogether IMHO contrary to freedev's contribution. Image() has better support in old trash browsers.

此外,虽然我喜欢 DOM,但旧的愚蠢浏览器可能会在您使用 DOM 时遇到问题,所以恕我直言,完全避免它与 freedev 的贡献相反。Image() 对旧的垃圾浏览器有更好的支持。

回答by freedev

This approach is a little more elaborate. Here you store all preloaded images in a container, may be a div. And after you could show the images or move it within the DOM to the correct position.

这种方法稍微复杂一些。在这里,您将所有预加载的图像存储在一个容器中,可能是一个 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;
}

Try it here, I have also added few comments

在这里试试,我还添加了一些评论

回答by naeluh

Here is my approach:

这是我的方法:

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

回答by Robin

Yes this will work, howeverbrowsers will limit(between 4-8) the actual calls and thus not cache/preload all desired images.

是的,这会起作用,但是浏览器会限制(在 4-8 之间)实际调用,因此不会缓存/预加载所有所需的图像。

A better way to do this is to call onload before using the image like so:

更好的方法是在使用图像之前调用 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;
}

回答by Amin NAIRI

Solution for ECMAScript 2017 compliant browsers

ECMAScript 2017 兼容浏览器的解决方案

Note: this will also work if you are using a transpiler like Babel.

注意:如果你使用像 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();

You could also have waited for all images to load.

您也可以等待所有图像加载完毕。

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

Or use Promise.allto load them in parallel.

或用于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);
}

More about Promises.

更多关于 Promise

More about "Async" functions.

有关“异步”功能的更多信息

More about the destructuring assignment.

更多关于解构赋值

More about ECMAScript 2015.

更多关于 ECMAScript 2015 的信息

More about ECMAScript 2017.

更多关于 ECMAScript 2017 的信息

回答by david_adler

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