如何为JS动态加载的外部图片配置preload优化PageSpeed检测
你现在的实现逻辑是JS执行时打乱图片数组、仅渲染第一张图到指定容器,浏览器默认要等这段JS解析执行完成后才会发起图片请求,比HTML解析阶段就发现的静态图片请求晚几百毫秒到几秒不等,这就是PageSpeed Insights提示需要预加载的根本原因。
以下是两种可直接落地的方案,根据你能修改的代码范围选就行:
方案1:页面head静态写入预加载标签(性能最好)
你当前总共只有4张候选图,单张尺寸仅300*145,体积极小,直接在两个站点页面的<head>标签内提前声明所有候选图的预加载规则即可。浏览器会在首屏资源加载的空闲阶段提前缓存这4张图,不管JS最终随机选中哪一张,都能直接从本地缓存读取,不会产生多余带宽浪费,也不需要修改你托管在第三方的现有脚本。
把下面的代码加到页面<head>里,把href替换成你imagesvar数组里对应的真实图片地址即可,注意地址必须和JS里给img赋值的src完全一致,差一个参数都无法命中缓存:
<link rel="preload" as="image" href="替换成你的第一张图片地址"> <link rel="preload" as="image" href="替换成你的第二张图片地址"> <link rel="preload" as="image" href="替换成你的第三张图片地址"> <link rel="preload" as="image" href="替换成你的第四张图片地址">
如果后续候选图数量超过10张、单张体积大于100KB,就不适合全量预加载了,你当前4张小图的场景完全没有性能负担。
方案2:动态注入预加载标签(无需修改站点页面代码)
如果你没法直接修改两个站点的页面源码,只能调整第三方托管的脚本,可以直接在现有脚本开头加一段动态生成预加载标签的逻辑,在打乱数组前就触发所有候选图的提前请求,比后续插入img标签的时机早,同样能实现预加载效果。
修改后的完整脚本如下:
var imagesvar = [ ["/goout/mylink/", "https://picsum.photos/300/145", "Title 1", "tracking-image"], ["/goout/mylink/", "https://picsum.photos/300/145", "Title 2", "tracking-image"], ["/goout/mylink/", "https://picsum.photos/300/145", "Title 3", "tracking-image"], ["/goout/mylink/", "https://picsum.photos/300/145", "Title 4", "tracking-image"], ]; // 新增:动态注入所有候选图的预加载规则 for (var i = 0; i < imagesvar.length; i++) { var preloadNode = document.createElement('link'); preloadNode.rel = 'preload'; preloadNode.as = 'image'; preloadNode.href = imagesvar[i][1]; document.head.appendChild(preloadNode); } function shuffle(b) { var j, x, i; for (i = b.length - 1; i > 0; i--) { j = Math.floor(Math.random() * (i + 1)); x = b[i]; b[i] = b[j]; b[j] = x; } return b; } shuffle(imagesvar); document.getElementById('div-to-load-external-image').innerHTML = '<a href="'+imagesvar[0][0]+'" target="_blank" rel="nofollow"><span class="myclass">New</span><div class="myimage" style="text-align:center;"><img fetchpriority="high" src="'+imagesvar[0][1]+'" width="300px" height="145px" alt="'+imagesvar[0][3]+'" onClick="gtag(\'event\', \'TodNav\', {\'event_category\': \'tod\',\'event_label\': \'tod-'+imagesvar[0][3]+'\'});" /></div><h2 class="title">'+imagesvar[0][2]+'</h2></a>';
这个方案只需要修改一次第三方托管的脚本,两个引用该脚本的站点会自动生效,我额外给img标签加了fetchpriority="high"属性,会告诉浏览器优先加载这张图,进一步提升加载速度,不会影响原有逻辑。
避坑提醒
- 不要尝试只预加载单张图:因为你是随机选图,单张预加载的命中率只有25%,PageSpeed还是会触发预加载提示
- 预加载标签的
as="image"属性不能漏写,漏写会导致浏览器重复发起两次图片请求,反而拖慢加载速度 - 跨域图片不需要给预加载标签加
crossorigin属性,普通静态图片默认不受跨域限制,加了反而可能导致缓存不命中
内容的提问来源于stack exchange,提问作者toscho

