图片的异步加载与onload函数

asynchronous

在之前的Promise应用场景与模块化尝试一文中提到过,图片加载之前用img.complete作为判断来决定是否异步加载图片,但是img.complete并不是特别靠谱的属性,所以再写一篇关于complete属性的文章,探究该属性的根源。

src与onload

例子1:

1
2
3
4
5
6
var img = new Image();
img.src = "logo.jpg";
img.onload = function () {
alert("image is loaded");
};
document.body.appendChild(img);

例子2:

1
2
3
4
5
6
var img = new Image();
img.onload = function () {
alert("image is loaded");
};
img.src = "logo.jpg";
document.body.appendChild(img);

IE9以下(IE < 9)的版本,例子1中的代码无法正常弹出.Chrome和Firefox下正常
因为logo.jpg是本地图片,导致浏览器加载起来非常快,几乎在给img赋值src的时候,图片就已经加载完成,同时触发了onload事件,代码中为onload赋值的语句就相当于在onload事件发生后,这时候已经晚了.所以正确的写法应该是第2个例子.既在给图片分配地址前,先绑定好它的onload事件,这样就不用担心错过时机的问题了.

缓存与onload

经过测试,IE7以上(>=7),Chrome,Firefox无论存不存在缓存,都会触发onload事件.

complete与onload

例子3:

1
2
3
4
5
6
7
8
9
10
11
12
13
function doIt () {
alert('do the job!');
}
img.src = "logo.jpg";
if (img.complete) {
alert("image is complete");
doIt();
} else {
img.onload = function () {
alert("image is loaded");
doIt();
};
}

Complete

1
2
3
4
5
The IDL attribute complete must return true if any of the following conditions is true:
1. The src attribute is omitted.
2.The final task that is queued by the networking task source once the resource has been fetched has been queued.
3.The img element is completely available.
4.The img element is broken.

上述四种情况都会导致complete变成true,而且complete在脚本执行的过程中可能会动态变化.

经过测试发现,如果src是有效的地址,那么IE,Chrome,Firefox行为一致:

1.IE 7-Edge,Chrome,Firefox 更改src后

1
2
立刻输出 complete === false
1s后输出 complete === true

如果src是无效地址,那么img.complete的值在不同浏览器下会有区别
1.IE 7-Edge 更改src后

1
2
立刻输出 complete === false
1s后输出 complete === false

2.Chrome,Firefox 更改src后

1
2
立刻输出 complete === false
1s后输出 complete === true

例子3能成功的原因是因为它是属于complete为true的情况之一,也就是completely available。假如是其他三种情况下或者是IE的不规范行为,都可能造成例子3的不一致。

总结

  1. onload函数要写在改变src前,这样确保了onload函数一定会被调用
  2. complete只是变向的在判断img是否已经触发了load事件,而且是不精准的判断
  3. complete在不同浏览器下,表现不一致,不建议使用
  4. 无论浏览器是否存在图片缓存,重新请求图片地址,都会触发onload事件

最后,如果有此类需求,建议采用例2中的代码,先绑定onload事件,在给定src值。