异步加载图片

51

如果我有如下的图像标签:

<img src="myimage.jpg" />

如果我在其中添加 "async":

<img async src="myimage.jpg" />

图片会异步加载吗?


<img src="myimage.jpg" loading="lazy" />。了解loading属性,请访问MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img - Zaheer
11个回答

50
异步加载(Lazy Load)内容的方法是不设置“src”属性,然后执行一个脚本,在DOM准备就绪时加载图像。
 <img data-lazysrc='http://www.amazingjokes.com/images/20140902-amazingjokes-title.png'/>

并且使用jQuery(或可能也可以使用纯JavaScript)使用下面的代码(建议在这里here):

<script>  
function ReLoadImages(){
    $('img[data-lazysrc]').each( function(){
        //* set the img src from data-src
        $( this ).attr( 'src', $( this ).attr( 'data-lazysrc' ) );
        }
    );
}

document.addEventListener('readystatechange', event => {
    if (event.target.readyState === "interactive") {  //or at "complete" if you want it to execute in the most last state of window.
        ReLoadImages();
    }
});
</script>

7
为什么这篇帖子会被踩却没有任何评论呢?代码完美运行并给予了问题提问者一个懒加载内容的解决方案。 - patrick
我反对你的脚本使用window load而不是dom-ready。Dom ready是$(document).ready(function() { ... })而不是$(window).load(function() { ... })。Window load比Dom ready晚触发。有关详细信息,请参见https://dev59.com/yGoy5IYBdhLWcg3wq_3O。 - B2K
这个确实可以工作,但它不符合W3C标准,因为img标签应该始终具有非空的src属性。 - Borjante
1
应该使用 lazysrc 而不是 lazyload,对吗? - Myoch
2
这将像defer一样工作,而非async。这两个属性之间有很大的区别。 - Bhavik Hirani
显示剩余4条评论

34

现代的做法是使用 loading 属性来加载图片和 iframe。

属性:loading=lazy

这将推迟元素的加载,直到它与视口的距离达到计算出的距离(这意味着,用户很可能会将其滚动到视图中)。

<img src="defer.png" loading="lazy" alt="An Awesome Image" width="500" height="400">

将属性设置为lazy会调用新的行为。

自 Chrome 76 开始已经支持,但可能要等到通过常规规范流程后才能在非 Chromium 浏览器中使用。

如果您要使用脚本进行延迟加载,最好使用带有lazy属性的图像并模拟该行为,而不是使用类名等方法。这样,当本地版本可用时,您可以让其接管。

强制急切加载

自动懒惰加载可能成为轻量级浏览的功能,在这种情况下,您可能希望反之强制加载图像。您可以使用相同的loading属性,并将其值设置为eager,即使浏览器否则可能选择不加载图像,也要请求它。

<img src="defer.png" loading="eager" alt="An Awesome Image" width="500" height="400">

更多阅读

查看WHATWG规范的拉取请求

附有关于懒加载图像和iframe的JavaScript备用方案的注释,请注意不要使用备用方案


自从这个被合并以后,这个答案应该被更新。 - mzrnsh

33
var img = new Image(),
    url = "myimg.jpg",
    container = document.getElementById("holder-div");

img.onload = function () { container.appendChild(img); };
img.src = url;

当您在脚本中请求图片时,这将立即开始加载图像,并在图像完成加载后,抓取并将其添加到其中。

还有许多其他方法可以实现此目的...
这只是异步加载单个图像的一个非常简单的示例。

但道义是:
为了使异步加载起作用,要么在 JavaScript 中加载它并使用 onload,要么在页面上包含图像标记,而不使用 src 属性(在 HTML 中指定 widthheight),然后在某个时间点返回 JS 并设置图像 URL。


1
接着我做了这个 <script async>var mybg = new Image(); mybg.src="/dir/to/image/mybg.png";</script>。之前主要是 CSS/JS。它只会加载一次图像文件。然后可以通过 CSS 或其他方式正常设置图像,例如作为背景。很少出现加载不完全的情况,但有时候会发生。 - Iacchus
1
@iacchus async 属性不适用于内联的 script 标签(没有 src)。 - Artur Aleksanyan

11

使用 Promise 在 JavaScript 中加载图像的另一种异步方式,它可以实现异步操作。

function asyncImageLoader(url){
    return new Promise( (resolve, reject) => {
        var image = new Image()
        image.src = url
        image.onload = () => resolve(image)
        image.onerror = () => reject(new Error('could not load image'))
    })
}    

// then use it like this

var image = asyncImageLoader(url)


image.then( res => {
    console.log(res)
})
  

你提到的 vanillaJS 库很受欢迎,但是在过去几年中,它的浏览器支持有些好坏参半,因此很多人不会依赖它。5年前,我会毫不犹豫地推荐使用 jQuery。 - jpaugh
1
@jpaugh 我想添加一个更新的答案来提到其他选择。我已经编辑了回答中的措辞以反映这一点 :) - anekix

8

3
有没有异步加载图片的方式? - amateur
6
据我所知,大多数浏览器都是异步加载图片的?! - nfo
1
图像标签支持一种提示,可以允许异步解码图像:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img#attr-decoding - derekbaker783

7

3
如果您正在使用jQuery,可以像这样做一些简单而有效的事情: HTML
<div data-lazy-load-image="/Images/image-name.png" data-image-classname="pop-in"></div>

JavaScript

$(function () {
    $("[data-lazy-load-image]").each(function (index, element) {
        var img = new Image();
        img.src = $(element).data("lazy-load-image");
        if (typeof $(element).data("image-classname" !== "undefined"))
            img.className = $(element).data("image-classname");
        $(element).append(img);
    });
});

CSS

@-webkit-keyframes pop-in {
    0% { opacity: 0; -webkit-transform: scale(0.5); }
    100% { opacity: 1; -webkit-transform: scale(1); }
}
@-moz-keyframes pop-in {
    0% { opacity: 0; -moz-transform: scale(0.5); }
    100% { opacity: 1; -moz-transform: scale(1); }
}
@keyframes pop-in {
    0% { opacity: 0; transform: scale(0.5); }
    100% { opacity: 1; transform: scale(1); }
}

你可以将此扩展以包括每个图像的其他可选属性,但你已经理解了这个想法。
这将等待DOM准备就绪,然后动态(异步)将图像加载到你用data-lazy-load-image属性标记的元素中。我包含了CSS使图像在加载时“弹出”。

如果您给出负面评价,我会很感激您能够留下评论,这样我就可以知道您认为答案需要改进或修正的地方。 - John Washam

2

虽然@Norguard的例子非常简单,足以处理一两张图像,但我发现echo.js对于延迟加载非常有用,https://github.com/toddmotto/echo

它可以使用数据-*属性来延迟加载图像,并且还带有其他一些很棒的功能。

<img data-echo="img/photo.jpg">
<script src="dist/echo.js"></script>
<script>
    echo.init();
</script>

1

我用jQuery采用了以下方法。

首先,不要在图片标签中使用“src”属性,而是将源放入不同的属性中,如下所示:

<img async-src="/mydirectory/myimage.jpg" />

然后,在jQuery文档准备好的函数中,我使用以下代码将元素的async-src复制到元素的实际src:

$("img[async-src]").each(function(index) {
    $(this).attr("src", $(this).attr("async-src"));
});

注:

jQuery的.each函数可能按照HTML/DOM中编码的顺序处理标签,但图像大小和网络问题可能意味着图像实际上不会顺序加载。换句话说,在第一个图像加载完成之前,第三个异步-src图像可能已经在屏幕上可视化出现。

如果您的页面布局依赖于该图像文件的像素尺寸 - 例如,您没有通过标记属性、CSS或父元素定义图像的尺寸 - 那么您可能需要在原始文件上使用“src”属性,指向您想要的空白白色或透明GIF的尺寸。

最后,如果您想在图像异步加载之后处理一些代码 - 例如处理淡入效果或更改与元素相关的CSS标签 - 请扩展jQuery如下:

$("img[async-src]").each(function(index) {
    $(this).load(function() {
        // code to run after loading
    });
    $(this).attr("src", $(this).attr("async-src"));
});

1
您可以阅读有关lazyload属性的更多信息:
<img src="myimage.jpg" alt="some description" lazyload/> - with default values

或者你可以设置优先级:

<img src="myimage.jpg" alt="some description" lazyload="1"/>
<img src="myimage.jpg" alt="some description" lazyload="2"/>

2
该规范已不再维护并已被废弃。http://www.w3.org/TR/resource-priorities/ - Don McCurdy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接