建站过程8-图片重加载

由于有些页面图片太多,图片服务器报错429,导致相应页面的某些图片只能显示难看的碎裂图标,本文将给出一个可能的解决方案。

问题

在配置完了图床,搭建好了博客之后,有一天我突然发现,主页上文章前面的缩略图没法全部加载出来!一看console发现原来是报了429的错误,简单地说就是请求数量太多了,以至于服务器都不接受了。这样一来主页上就老是有一些难看的碎裂图标,这让有强迫症的我十分难受,于是我打算好好解决一下这个问题。

429-加载失败

最开始的想法是,会不会图片太大了,拖慢了加载进度?之前已经用tinypng压过图了,最大的图片也只有1MB出头,我实在不知道该怎么进一步压缩。后来经过多方查找,我终于找到了一个比较良心的压缩图片网站OKTools,然后进一步压缩到每张图片0.5MB,费了老大劲,但是仍然没能解决429错误。后来还是突发奇想,可以在加载失败后等一段时间再重新加载,这样就不会因为同时请求太多导致服务器不接受了。

解决方案

废话少说直接上代码:

主要代码部分

1
2
3
4
5
6
7
8
9
const imglist = document.querySelectorAll("img");
reload_exclude();
for(var ind=0;ind<imglist.length;ind++){
let img = imglist[ind];
//注意js中==会尝试将字符串转化为数字再进行比较
if(img.getAttribute("reload-exclude")==1){continue;}
img.setAttribute("retry",0);
img.onerror=(e)=>{reloadimg(img);};
}

这一部分的功能主要是:

  1. 选择所有<img>标签;
  2. 对于某些图片,标记exclude,表示不执行重加载;
  3. 对所有没有标记的图片,设置初始尝试次数retry=0,并绑定加载失败回调函数;

回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function reloadimg(img) {
let retry = parseInt(img.getAttribute("retry"));
// 开启一个定时器,这里每1500ms执行一次
let timer = setTimeout(() => {
if (retry > 2) { // 如果重试次数大于2
console.log("连接失败");
img.src = // 图片使用占位图片url
"https://www.wetools.com/imgplaceholder/800x400?text=图片太帅,无法显示";
img.onerror = null;//防止占位图片也失效,从而无限循环
clearTimeout(timer);// 清除定时器
} else {
// 重试次数在规定内
console.log("重试次数", retry+1);
// 计数器+1
retry += 1;
img.setAttribute("retry", retry);
img.setAttribute("src",img.src); //重新加载
}
}, 1500);
}

主要思路:

  1. 取出retry变量的值,然后判断尝试次数是否已经超过2
  2. 如果超过,使用占位图片;注意此时最好把回调函数给清除,防止占位图片也失效导致回调函数一直调用
  3. 否则每隔1.5s重新加载图片一次

排除

在友链页面,已经设置了头像图片加载失败时的默认图片,没必要再采用重新加载的方法,因此标记reload-exclude

1
2
3
4
5
6
7
//添加一些排除标记
function reload_exclude(){
let excld = document.querySelectorAll(".link-avatar img");
for(var i = 0;i<excld.length;++i){
excld[i].setAttribute("reload-exclude",1);
}
}

(6.26更新)

发现这样由于重加载图片都是在1.5s之后,很容易再次引发扎堆访问,因此重试时间增加随机性会是一种更好的选择。

此处我们复用了say.js中的随机数生成函数,将上面的1500改成500*randomNum(2,5),也即随机等待1~2.5s,这样不同图片的重加载时间就可以错开了


建站过程8-图片重加载
https://www.hovering-clouds.cn/space/2022/07/01/建站过程8-图片重加载/
作者
垂云
发布于
2022年7月1日
许可协议