问题描述
简短问题
我如何(尽可能可靠地)计算“首屈一指”的内容的视觉效果,包括外部CSS和所应用的字体以及加载的所有图像。
完整问题
抱歉,这个问题有很多,我只是想表明我曾在这个问题上工作过,而且我在哪里工作,所以它并没有最终成为“我该如何做”类型的问题,并没有得到即时调查!!
我正在尝试确定是否可以在客户端浏览器中完全下载呈现“首屏”内容所需的所有资源。
这是纯粹使用浏览器API(即不使用屏幕快照时间轴)模拟SpeedIndex的更大目标的一部分。
我需要收集的东西
我无法克服的挑战
- 必须运行使元素多次折叠的功能
- 确保所有关键资产实际上都以非常慢的连接加载。
- 确保该功能在网络流量很高时运行,如果网络上从来没有一个安静的2秒窗口(可能是由于每秒进行一次轮询服务器的老式聊天),它将永远不会触发。
首先,这不一定是完美的,这是一个近似值,但是我越精确,它就会越好!
此刻我的操作方式是使用PerformanceObserver
列出所有下载的资源。
第二秒钟,我得到一个2秒的窗口,其中没有完成任何请求,我假设关键的CSS已下载并开始查看页面上的图像。
//getRects is the function to get all of the rectangles above the fold.
var rectInterval = setTimeout(getRects,2500);
var xx = new PerformanceObserver(function (ll,p) {
ll.getEntries().forEach(function (en) {
if (en.name.indexOf(apiEndpoint) == -1) {
if (en.entryType == "layout-shift") {
if (en.entryType == "resource"){
//any resources I reset the timer waiting for a quiet time
clearTimeout(rectInterval);
rectInterval = setTimeout(getRects,2000);
}
}
});
});
xx.observe({
entryTypes: ['largest-contentful-paint','longtask','resource','paint','navigation','mark','measure','layout-shift','first-input']
});
我使用getRects
在函数getBoundingRect()
中捕获页面上所有图像和带有背景图像的元素的尺寸,然后使用window.innerHeight
等来计算它们是否出现在折叠上方。 / p>
这些是下载时要检查的候选人(以及以前的资源列表等)
var doc = window.document;
var browserWidth = window.innerWidth || doc.documentElement.clientWidth;
var browserHeight = window.innerHeight || doc.documentElement.clientHeight;
function checkRectangle(el){
var rtrn = false;
if (el.getBoundingClientRect) {
var rect = el.getBoundingClientRect();
//check if the bottom is above the top to ensure the element has height,same for width.
//Then the last 4 checks are to see if the element is in the above the fold viewport.
if (rect.bottom <= rect.top || rect.right <= rect.left || rect.right < 0 || rect.left > browserWidth || rect.bottom < 0 || rect.top > browserHeight) {
rtrn = false;
}else{
rtrn = {};
rtrn.bot = rect.bottom;
rtrn.top = rect.top;
rtrn.left = rect.left;
rtrn.right = rect.right;
}
}
return rtrn;
}
//function to get the rectangles above the fold
function getRects(){
var rects = [];
var elements = doc.getElementsByTagName('*');
var re = /url\(.*(http.*)\)/ig;
for (var i = 0; i < elements.length; i++) {
var el = elements[i];
var style = getComputedStyle(el);
if(el.tagName == "IMG"){
var rect = checkRectangle(el);
if(rect){
//The URL is stored here for later processing where I match performance timings to the element,it is not relevant other than to show why I convert the `getBoundingClientRect()` to a simple object.
rect.url = el.src;
rects.push(rect);
}
}
//I also need to check for background images set in either CSS or with inline styles.
if (style['background-image']) {
var rect = checkRectangle(el);
if(rect){
var matches = re.exec(style['background-image']);
if (matches && matches.length > 1){
rect.url = matches[1].replace('"','');
rects.push(rect);
}
}
}
}
那一点很好(尽管有一些缩小搜索范围的技巧,所以我不会遍历所有内容都很好),但是我的问题来自加载缓慢的网站。如果请求之间的间隔超过2秒(这种情况可能发生在特别慢的连接上,或者如果服务器离用户很远),那么我将无法获得完整的数据。
我的解决方法是然后监视其他网络请求(但再次等待两次请求之间的延迟2秒),然后重新运行该功能以收集上述折叠内容。如果该网站在滚动上使用延迟加载,这显然不能很好地工作,因为请求可以在整个页面生命周期中不断触发。
由于在一个非常沉重的页面上收集元素的尺寸可能会占用大量cpu,并且需要将此数据发送到服务器进行分析,因此我正在尝试找到一种更可靠的方法来确保所有或仅触发getRect
一次但确保所有初始加载完成的方式。
假设如果有效负载足够小(例如小于1kb),则可以在服务器上稍后对数据进行任何处理
我考虑过的事情
- 寻找任何
<links>
,<scripts>
等,并检查它们是否已加载。该问题来自于动态添加的链接以及外部资源(即,在另一个样式表中链接的样式表)。这可能会更健壮,但会变得非常复杂。 - 将两次检查之间的时间(我等待的安静时间)设置得更长一些。显然,由于“安静时间”可能永远不会发生,因此交通繁忙的网站的问题更加严重。
- 使用
MutationObserver
监视页面,然后再次等待安静的时间。但是,据我所知,如果页面具有任何交互性,则会更频繁地触发该事件? - 我知道,对于正确内联CSS的网站,我的方法会产生过多报告,这不是问题。
我是否走上正轨,可以解决这个难题,或者我可以根据window.performance
数据(或类似的API)使用一些简单的公式,让我说“所有折叠元素都是加载并呈现。”
我希望这很清楚,但是任何问题都可以问,因为我知道这个问题中有很多内容可以简单地回答“如何检查所有关键资源是否已加载”。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)