文共4167字,预计学习时长11分钟
图源:turnkeyInternet
查询谷歌会发现很多文章指出2到5秒钟网页就能加载完毕。但是,是什么使2-5秒成为预设范围呢?直觉告诉你,答案必定比这更复杂。没错,真正的答案比任何试图解答的时间范围细微得多,问题出在提问本身。
并非所有网站和访问者都一样
这个问题有一个缺陷,即认为在不同情况下可采用同一标准。网站不同,用户访问网站的网络情况也不尽相同。
静态博客与图形编辑器不同,4G比2G快得多。静态博客可能根本用不到JavaScript,图形编辑器却会大量使用。4G网络访问者可能只会遇到50毫秒的延迟,而2G用户每次往返可能会经历整整一秒钟的时间。
上表描述了理想条件下达到的数据速率。地下车库不是理想环境,但每个人都有可能会遇到这样的情况,这意味着用户访问网站所使用的网络条件千变万化。
网络条件的可变性
调整网络状况会导致页面加载时间截然不同。假设有两个用户要通过移动网络访问笔者的个人网站(davidea.st)。它只是一个静态网站,不会阻断JavaScript。index.html文件大小只有2.3kb,CSS的大小是1.8kb。
第一个用户以400kib的带宽(2G速度)但100ms的延迟(4G速度)访问。第二位访问者以400kib的带宽,但有1000ms的延迟(均为2G速度)访问。
使用同一网站,调整延迟(当人在停车场时延迟就会很容易调整)使index.html的加载速度慢了十倍。因此,如果仅考虑网络延迟就可以彻底改变同一站点的页面加载速度,只是提问“网站应该以多快速度加载”有意义吗?
开发人员无法控制用户进入的网络。这意味着判定网络性能并不仅仅是了解网站加载时间的固定数字。而是要知道页面加载发生在不同条件下的不同时间段,知道这一点的唯一方法是测量。
RUM:测量现实世界性能
这正是RUM监控所能提供的。RUM或“真实用户指标”,从页面加载中收集重要的性能指标并将其信标到可以查看仪表盘数据的服务器。RUM供应商的形状和大小各不相同,就本文而言,笔者将使用FirebasePerformance Monitoring。
Web性能是一种分布
想象一下,如果记录了访问网站的用户的首次渲染时间。然后,将时间记录在条形图中,如下所示:
但是,如此呈现的视觉效果并不准确,并非所有用户都将在完全相同的时间段内加载网站。一个人的网站加载时间为1.5秒,下一个人的网站加载时间为1.65秒。因此,可以使用面积图代替条形图。
该面积图显示了加载时间的分布,可以帮助了解加载时间的范围以及最常见的情况,它代表所有加载时间的百分位。
Firebase Performance Monitoring为不同指标提供了一个完整的面积图仪表板。
x轴代表更大的加载时间数组,y轴表示百分位数,这些百分位数最有趣的是它们的形状。
尾部
图表开始急剧向上弯曲,然后缓慢向下弯曲,形成尾巴形状。这说明大多数用户的加载时间在1.5到3.5秒之间。这很好,但是不要被这种变化所骗,尾部包含所有问题。
尾部表示遇到最长加载时间的用户。尾部越长,波动性越大。这意味着网站性能变得难以理解。有些用户加载很快,有些载入缓慢。因此,我们需要努力缩短尾部,也需要了解尾部代表什么。
网站何时可用?
当大多数人说“页面加载”时,指的是该站点实际可用的时间。这有点误导人,因为网站不必完全加载。
想想一个报导重大事件的实时流媒体博客。访问它时发现,屏幕上神奇地出现了超时更新。该页面什么时候“加载”?当第一次更新出现时吗?当header加载时是吗?并非人人都想细究这一话题,可以将页面加载细分为更具体的指标。
“页面加载”的指标
用户启动网站加载时会使用到导航,这可能是通过键入URL并单击Enter或单击链接生效。没有渲染像素,浏览器通过网络获取资源。
初次渲染(FirstPaint, FP)是引用的最常见指标之一。它只会问:屏幕上何时出现普通的像素?了解像素何时开始出现很重要,因为可以了解用户开始看到画面的速度。在某些情况下,此反馈可以帮助用户知道该网站正在加载,因而继续等待。
如果要构建传统的服务器端渲染网站(与服务器端呈现JavaScript应用程序不同),则First Paint可以准确地表示“页面加载”。这是因为所有HTML和CSS都可以使用,无任何渲染阻止JavaScript。但这对于依赖JavaScript的网站可能有所不同。
在很多单页应用(SPA)网站的情况下,First Paint用于静态元素,例如页眉和页脚。该应用程序的其余部分仍在启动,等待JavaScript加载和执行。用户可能会看到一些东西,但该应用程序尚未可用。
首次有内容的渲染(FirstContentful Paint,FCP)关注的是设计内容何时出现在页面上。这不仅仅是渲染到屏幕上的像素。如果网站加载速度很快,FCP和FP往往会同时启动。但如果阻止了Web字体的文本呈现,或者当内容需要JavaScript来加载和执行时,FCP可能会落后于FP。
即使网站加载速度缓慢,FCP和FP的速度也可以相同。这是大型JavaScript应用程序的常见现象,这些应用程序无法渲染或渲染太多静态HTML。在这种情况下,当JavaScript最终加载,执行并呈现FP和FCP时,往往会同时触发它们。
domInteractve表示浏览器已经从静态HTML构建了DOM树。然后,浏览器开始加载其他资源,例如样式表,图像和JavaScript,这对于了解何时构造DOM树以及何时浏览器将开始加载其他所有内容很有用。
何时知道重要的资源(如JavaScript和样式表)已加载?这就是domContentLoadedEventEnd 的目的。当domContentLoadedEventEnd触发时,不再有任何样式表阻止任何JavaScript执行。这些度量标准非常有用,domInteractive 会说明何时开始加载样式表,而domContentLoadedEventEnd 会说明何时结束加载。
“加载事件结束”(Load Event End)不一定总是最有用的指标,但有时它可以提供很多信息。文档加载完成后,将触发loadEventEnd事件。这意味着当DOM树中的所有资源都已加载时将触发该事件。所有链接的样式表、脚本和图像、图片等资源可能会降低此指标的速度,如果不小心将100MB GIF上传到网站,则会看到相当慢的loadEventEnd。
此指标可帮助大致了解文档资源的加载时间。在触发此指标之前,网站可以使用很长时间。
首次输入延迟(FirstInput Delay,FID)用于测量首次用户交互触发所花费的时间。用户可能停留在看起来可以使用但已冻结的页面上,无论进行多少次滑动或点击,该网站都无法正常工作,这时需要“首次输入延迟”来测量此类问题。
如果有静态博客,它就也许没那么有用,因为FID可以测量用户何时可以与网站进行交互,这通常是在事件监听器触发后触发的。现在,对于重型JavaScript应用程序,该指标也很关键。JavaScript繁重的应用程序必须先加载、解析和执行,然后才能运行,这可能会推迟网站的最初交互时刻。
WebVitals
如果你是一个精通性能的开发人员(或者如果关注过大牛Addy Osmani),那么你可能听说过Web Vitals计划。Web Vitals是Google的一项举措,旨在为质量信号提供统一指导,这对于在网络上提供出色的用户体验至关重要。
其目的是提高加载性能、交互性和稳定性。构成Web Vitals的核心指标是:
· 最大内容渲染(LCP)(测量加载性能)
· 首次输入延迟(测量交互性)
· 累积版式移位(CLS)(测量稳定性)
笔者不会详细介绍每个指标(因为已经介绍了很多指标),但是可以在web.dev/vitals上查看说明。每个指标都是通过Google网络小组提供的库检索的。
import { getCLS, getFID,getLCP } from 'web-vitals';getCLS(console.log);
getFID(console.log);
getLCP(console.log);
Firebase性能监控仅支持将“首次输入延迟”作为一流指标。在自动收集其他项目之前,可以使用“自定义跟踪”记录最大的内容丰富的渲染和累积版式移位。
指标过载
借助Performance Monitoring,可以使用属性来细分性能数据,并专注于应用程序在某些情况下的性能:firebase.google.com。
Web性能处处是指标,但并非所有指标都对网站和个人情况有用。笔者建议你去了解一下,看看它如何为你的网站类型服务。不用担心追踪所有指标,只要了解哪种方法最适合网站。
网站应该以多快速度加载?
如何处理这些指标?你可以使用它们来了解网站上发生的情况并提出更好的问题。有个问题必然要问:“使用3G访问用户何时首次看到内容?”追踪这些指标可以查看受影响的用户类型以及随着时间推移的趋势。
借助FirebasePerformance Monitoring,可以深入了解诸如First Contentful Paint的指标,查看哪些维度会影响指标。在这种情况下,可以按有效连接类型(网络速度)将其拆分。
仪表板显示大多数用户至少使用4G或更快的连接网络。但是,有5.88%的用户使用3G速度并在2.24秒内加载网页。这样比问“网站应该以多快速度加载?”要好得多。
永远记住,网页加载的速度并非确定数值,Web性能本身就是一种分布。需几行代码,测量可以帮你提出更好的问题并获得更好的答案。
留言点赞关注
我们一起分享AI学习与发展的干货
如转载,请后台留言,遵守转载规范
于做网站的需求越来越大,每个企业都想找一家可靠又有效率的的网站建设公司,对于这个要求,作为一个建站公司来说一定先要做到一点,这样方可能确保建站时间的效速,那就是建站的时间。建站公司都希望建设网站的时间快,为什么这样说呢?因为建站时间快那么会给建站公司省工时,同时也有提高工作效率。但是建站时间来说不单只有一个原因,还有多方面的因素,比如UI稿设计、网站代码编写、网站上线、网站验收这都是要时间,对于时间方面建站公司给出一般都在于15到20个工作日来计,为什么要这么久呢?原因在会在哪呢?今天西安网站建设公司一度互联小编来和大家分享一下在西安网站建设一般要多久:
一、UI设计时间
为什么谈到UI设计,当然一个正常网站一定要有页面设计的,一个网站好与坏都在UI方面体现的,对于UI方面设计时间要多久呢?在这方面当中要5到8个工作日,这也是UI设计常规的时间,要想做好网站这也是必然的第一步。
二、代码程序编写时间
网站的组成是CSS+DIY+HTML+JS写这些代码都要时间的,每一个网站的页面都是一步一个代码组成的,这也是一个重点原因之,在写这些代码都要花4到6个工作才能完成,所以一个网站组成的结构非常多,写代码时工程师都是一步一个脚印来写的。
三、网站测试时间
网站完成后为什么还要测试呢?其实上网站测试是非常重要的一部份,所有问题都是在于网站测试才能体现出来的,那么测试时间要多久呢?相对来说要2个工作日成能完成的,这时间都是在寻找问题,找到问题后工程师还要一个一个来修复。
通过以上三点总结,我相信到大家都明白了,建站时间要多久了。其实上建站是急不来的都要有个过程的,不是一两下就完事了,如果你明白后心里都有个数,这也帮你明白建站过程的时间,你可以更好的来规划建站时间
如果您以前问我这个问题,我会说,肯定很难吧,我们用用开源项目就好。
何必重复造轮子?
应不应该重复造轮子呢?
我想每个人心中都有答案。但是我鼓励大家,我们一起重复造轮子。
后续会出一篇文章,关于Chat的文章。是的,不是ChatGPT,是Chat,没有机器学习,我们普通研发人员,也应该继续前进,当然还是和正则表达式有关系。
现在,我们回到今天的话题,正则表达式实例与HTML语法树。
前面的文章,我们知道了,怎么匹配HTML标签,怎么匹配HTML标签属性,今天我们从零实现一个HTML语法树。
看这篇文章之前,建议先看前面两篇文章,如果您对正则非常熟悉,那么现在就开始吧。
在开始前,我们需要整理需求,我们需要知道,一个完整的HTML文档,最基本的语法,标签以及不同框架增加的特殊属性等,我们因该如何去匹配实现。
为什么要加上其它框架属性,因为当时想通过一套代码生成VUE、React版本。[我想静静]
下面截图文档中,基本囊括了,一个HTML文档的所有情况信息,您可以仔细看下。其中包括(注释、文档声明、单标签、双标签、样式、脚本、有属性值属性、属性名即属性值属性、第三方框架属性等)。
需求文档图
<!-- 这是一段注释。
写好一个AST,让组件一套代码,
同时支持服务端渲染,前端渲染,是否可行? -->
const reg_comment=/<\!--.*?-->/s;
<!DOCTYPE html>
const reg_doctype=/<!doctype[^<>]*>/i;
<div><input />
const reg_element=/<[^\/\!]((["'])+.*?|[^>])+>/
</div>
const reg_elementEnd=/<\/.*?>/
<div></div>
var reg_tagName=/(?<=<[\/\s]*)\w+(?=(\s+(?![\s=])|>))/;
<input type='text' disabled value="" class="txt txt-md" v-on:click="save('button')" />
const reg_tagAttrs=/(?<=\s)[\w:\.\-@]+(=(["']).*?)*/g;
v-on:click="save('button')"
var reg_tagAttrDatas=/(^[^=]+|(?<=(['"])).*?(?=))/g;
查阅了相关资料、同时编写Demo案例验证、对于Javascript版本的正则表达式,发现对于嵌套匹配目前支持不完善,所以放弃这种方式。
当然,也有可能,我挖掘的还不够深入。
怎么理解?
请看下面的例子。
<!-- 这是一段注释。
写好一个AST,组件一套代码,
同时支持服务端渲染,前端渲染,似乎可行? -->
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<title>沧海一站</title>
<style type="text/css">
html,body {width: 100%;height: 100%;margin: 0;padding: 0;}
</style>
</head>
</html>
看到这个例子,你大概明白。就是一行一行的匹配,或者说每次只匹配一种类型。
1、遇到非input、img、link、hr、br这几个单行标签,或者</>结束标记,就向下递归。
2、遇到结束标记</>,就返回上一层。
3、遇到style、script标签,他们内部的内容,直接按文本处理。
到这,我想部分朋友,都不需要看代码实例,都知道怎么实现了。
测试代码从PrvtCMS中,临时拆分出来的,只要思路有了,实现起来还是很容易。
const reg_tagName=/(?<=<[\/\s]*)\w+(?=(\s+(?![\s=])|>))/;
const reg_tagAttrs=/(?<=\s)[\w:\.\-@]+(=(["']).*?\2)*/g;
const reg_tagAttrDatas=/(^[^=]+|(?<=(['"])).*?(?=\2))/g;
const regMap=new Map();
regMap.set("element", /^<[^\/\!]((["'])+.*?\2|[^>])+>/);
regMap.set("elementEnd", /<\/.*?>/);
regMap.set("note", /<\!--.*?-->/is);
regMap.set("declare", /<!doctype.*?>/i);
regMap.set("text", /^[^<>]+/);
/**
* 返回Json语法树
* @param {父节点名称} name
* @param {被解析的html} htmlContent
* @param {节点集合} nodes
*/
const toJson=(name, htmlContent, nodes)=> {
regMap.forEach((value, key)=> {
if (key !=="elementEnd") {
let res=regFirstResult(value, htmlContent);
if (res.length) {
htmlContent=toNext(name, res, key, htmlContent, nodes);
}
}
});
// 处理同级
let res=regFirstResult(regMap.get("element"), htmlContent);
if (res.length) return toJson(name, htmlContent, nodes);
return htmlContent;
};
/**
* 下一匹配
* @param {父节点名称} name
* @param {匹配结果} parseRes
* @param {匹配类型} nodeType
* @param {被解析的html} htmlContent
* @param {节点集合} nodes
* @returns
*/
const toNext=(name, parseRes, nodeType, htmlContent, nodes)=> {
if (nodeType=="elementEnd")
return parseElementEnd(name, parseRes, nodeType, htmlContent, nodes);
if (nodeType=="element")
return parseElement(name, parseRes, nodeType, htmlContent, nodes);
return parseText(name, parseRes, nodeType, htmlContent, nodes);
};
const nodes=[];
toJson("", strHtml, nodes);
console.log(JSON.stringify(nodes));
结果图
了解或者使用Svelte、Angular、Vue、React、Htmx、Qwik、Astro、Web Component等等技术,AST似乎无处不在。
所以一起重复造轮子吧。
PrvtCMS模板在线管理、支持实时预览、跨模板、跨组件引用等。能实现这些功能的基础就是写了一个HTML语法树。是的,重复造轮子。
功能截图
……思考中……
人人为我,我为人人,欢迎您的浏览,我们一起加油吧。
*请认真填写需求信息,我们会在24小时内与您取得联系。