目录
2、从URL输入到浏览器发生的所有过程中,哪些可以进行性能优化
5.写实现一个request,可以在失败的时候重试,有interval和maxCount参数 : oc
1、FMP指标在中后台场景的意义,为什么不用LCP处理
Web前端最新优化指标:FP、FCP、FMP、LCP、TTI、CLS、FID、FPS等
用户体验指标:
-
TTI:首次可交互时间,连续五秒内没有长任务和两个以上的 GET 请求时,那五秒前的最后一个长任务结束时间就是 TT 记录的时间
-
FID:首次可交互时间,连续五秒内没有长任务和两个以上的 GET 请求时,那五秒前的最后一个长任务结束时间就是 TT 记录的时间
-
TBT:阻塞总时间,记录在 FCP 和 TTI之间长任务的阻塞时间
-
FP:首次绘制,页面第一次绘制元素的时候
-
FCP:首次内容绘制,首次绘制文本、图片、非空白 Canvas 或 SVG的时间
-
LCP:最大内容绘制,视窗内最大的元素绘制的时间
-
CLS:累计位移偏移,记录了页面上非预期的位移波动CSDN9
加载性能指标
- FMP(First Meaningful Paint),首次渲染有意义的内容的时间,“有意义”没有一个标准的定义,FMP的计算方法也很复杂。
- 优点: FMP是一个早期的性能指标,可以快速反馈页面内容的初步加载情况。
- 缺点: FMP的检测较为复杂,容易受广告和异步内容影响,因此不稳定且难以标准化。
- LCP(largest contentful Paint),最大内容渲染时间。
- 优点: LCP更稳定,容易测量,并且能更好地反映用户感知到的页面加载速度。
- 缺点: 作为较晚期的指标,LCP可能不能及时反映页面初始加载的体验。
中后台场景的意义
在中后台(B2B、内部系统、管理后台等)场景中,FMP和LCP的使用意义和取舍需要根据实际需求来决定
- 用户期望:
- 中后台用户:通常更注重功能性和数据加载速度,要求快速访问和操作,而不太关注页面的初步视觉加载
- 前台用户:一般更关心页面的感知加载速度和初次内容展示。
- 指标选择
- FMP在中后台场景中的意义:尽管FMP在前台体验优化中较为常用,但在中后台场景中,用户可能更关注页面是否能尽快显示主要内容和进行操作。FMP能帮助开发者了解页面主要内容的首次呈现时间。
- LCP在中后台场景中的意义:LCP能更好地反映页面的最终加载状态。如果页面包含较大图表或数据表,LCP能帮助评估这些元素的加载时间,确保用户能尽快看到完整的数据。
- 为什么不使用LCP处理
- 数据密集型应用:中后台系统通常包含大量的数据展示,初始内容(如表单、表格、仪表盘)较早展示给用户很重要,而不是等待所有内容加载完毕。
- 交互优先:中后台用户往往需要快速的响应和操作,FMP提供了一个早期的内容展示时间点,可以优化初始交互体验。
- LCP稳定性:尽管LCP更稳定,但对于数据量大、内容复杂的后台系统,LCP可能会推迟性能反馈时间,使得优化措施更难实施。
2、从URL输入到浏览器发生的所有过程中,哪些可以进行性能优化
URL所有过程:
- DNS解析:当用户在浏览器中输入一个URL时,浏览器首先会进行DNS解析,将URL中的域名解析成对应的IP地址。
- TCP连接:当DNS解析完成后,浏览器会与服务器建立TCP连接。
- HTTP请求:浏览器通过TCP连接向服务器发送HTTP请求,请求服务器返回相应的页面内容。
- 服务器响应:服务器收到HTTP请求后,会处理请求并返回响应内容,包括HTML代码、CSS样式、JavaScript脚本等。
- 浏览器解析:浏览器收到服务器响应后,会解析HTML代码、CSS样式和JavaScript脚本,并将它们转换为可视化的页面。
- 页面呈现:当浏览器解析完成后,页面就会呈现给用户。
- 用户在浏览器地址栏输入URL回车
- 输入后 --> 网络进程,网络收到URL请求后查看是否缓存了该资源
- 缓存了该资源:返回给浏览器
- 未缓存该资源:网络进程向服务器发起HTTP请求(网络请求)以请求资源
- DNS解析:将域名解析成IP地址
- 如果请求协议是HTTPS,那么还需建立TLS连接
- 利用IP地址和服务器建立TCP链接,浏览器与服务器进行三次挥手
- 浏览器构建请求头信息,并将其发送给服务器
- 服务器处理请求并放回HTTP报文给网络
- 处理状态码
- 缓存分为:强缓存和协商缓存
- 断开连接:TCP四挥手
- 浏览器进程检查当前的URL是否和之前打开的渲染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程。
可以进行性能优化的方面:
- DNS解析:
- DSN预解析:使用
标签提前解析DNS。<link rel="dns-prefetch" href="//example.com">
- 使用快速DNS服务:选择响应速度快且稳定的DNS服务提供商。
- 内容分发网络(CDN):使用CDN可以显著减少DNS解析时间。
- CDN:它采取了 分布式网络 缓存结构(即国际上流行的web cache技术),通过在现有的Internet中增加一层新的网络架构,将网站的 内容发布 到最接近用户的cache服务器内,通过 DNS负载均衡 的技术,判断用户来源就近访问cache服务器取得所需的内容,解决Internet 网络拥塞 状况,提高用户访问网站的响应速度,如同提供了多个分布在各地的加速器,以达到快速、可冗余的为多个网站加速的目的。
- DSN预解析:使用
- 优化关键资源:关键资源是指那些对页面加载速度影响最大的资源,通常包括HTML、CSS、JavaScript脚本、图像和视频等。
- 使用CDN:CDN可以将关键资源缓存到全球各地的服务器上,从而加快资源的加载速度。
- 延迟加载非关键资源:对于那些对页面加载速度影响较小的资源,可以采用延迟加载策略,在页面加载完成后再加载这些资源。
- 合并关键资源:将多个关键资源合并成一个文件可以减少HTTP请求的数量,从而加快加载速度。
- 压缩关键资源:通过压缩关键资源可以减少它们的体积,从而加快加载速度。常用的压缩工具包括Gzip、Brotli等。
- 减少重绘和重排:重绘是指浏览器重新绘制页面内容,而重排是指浏览器重新计算元素的位置和大小。重绘和重排都会对页面的加载速度造成影响。为了减少重绘和重排,可以采取以下策略。
- 避免使用不必要的动画和过渡效果
- 避免频繁更改元素的属性
- 使用flexbox和grid布局
- 优化CSS选择器
- 优化CSS和JavaScript:CSS和JavaScript脚本也是影响页面加载速度的重要因素。为了优化CSS和JavaScript。
- 使用CSS预处理器:CSS预处理器可以帮助我们编写更简洁、更易维护的CSS代码。
- 使用JavaScript模块化工具:JavaScript模块化工具可以帮助我们将JavaScript代码分解成更小的模块,从而加快加载速度。
- 压缩CSS和JavaScript:通过压缩CSS和JavaScript代码可以减少它们的体积,从而加快加载速度。
3、细谈 vue - component(组件)
在Vue.js中,组件(component)是构建用户界面的基本单位。组件可以看作是独立的、可重用的界面元素,能够包含逻辑、模板和样式。Vue组件通过组合形成一个完整的应用,增强了代码的可维护性和可重用性。以下是Vue组件的详细解析。
-
组件的定义和注册
- 全局注册组件:全局注册的组件可以在任何Vue实例的模板中使用。
-
// 定义一个名为 my-component 的组件 Vue.component('my-component', { template: '<div>A custom component!</div>' }); // 创建一个根实例 new Vue({ el: '#app' });
- 局部注册主键:局部注册的组件仅在当前的Vue实例或组件中可用。
-
var ChildComponent = { template: '<div>A custom component!</div>' }; new Vue({ el: '#app', components: { 'my-component': ChildComponent } });
-
组件的基础结构
- 模板(templa):描述组件的HTML结构
- 脚本(script):包含组件的数据、方法、生命周期钩子等逻辑
- 样式(style):定义组件的css
-
<template> <div> <h1>{{ message }}</h1> </div> </template> <script> export default { data() { return { message: 'Hello, Vue Component!' }; } }; </script> <style scoped> h1 { color: blue; } </style>
-
组件间通信
- 父组件向子组件传递数据(Props)
-
<!-- ParentComponent.vue 父组件 --> <template> <div> <child-component :message="parentMessage"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { 'child-component': ChildComponent }, data() { return { parentMessage: 'Hello from Parent' }; } }; </script>
-
<!-- ChildComponent.vue 子组件 --> <template> <div> <!-- 子组件通过模板语法进行绚烂 --> <p>{{ message }}</p> </div> </template> <script> export default { <!-- 子组件通过props接收父组件传递过来的数据 --> props: ['message'] }; </script>
-
子组件向父组件传递消息(Events)
-
<!-- ParentComponent.vue --> <template> <div> <child-component @my-event="handleEvent"></child-component> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { 'child-component': ChildComponent }, methods: { handleEvent(data) { console.log(data); } } }; </script>
-
<!-- ChildComponent.vue --> <template> <div> <button @click="sendMessage">Send Message</button> </div> </template> <script> export default { methods: { sendMessage() { this.$emit('my-event', 'Hello from Child'); } } }; </script>
-
插槽
- 插槽用于在子组件中嵌入父组件的内容。Vue提供了默认插槽、具名插槽和作用域插槽。
- 默认插槽
-
<!-- ParentComponent.vue --> <template> <div> <child-component> <p>This is some slot content</p> </child-component> </div> </template>
-
<!-- ChildComponent.vue --> <template> <div> <slot></slot> </div> </template>
-
具名称插槽
-
<!-- ParentComponent.vue --> <template> <div> <child-component> <template v-slot:header> <h1>Header Content</h1> </template> <template v-slot:footer> <p>Footer Content</p> </template> </child-component> </div> </template>
-
<!-- ChildComponent.vue --> <template> <div> <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </template>
-
作用域插槽
-
<!-- ParentComponent.vue --> <template> <div> <child-component> <template v-slot:default="slotProps"> <p>{{ slotProps.text }}</p> </template> </child-component> </div> </template>
-
<!-- ChildComponent.vue --> <template> <div> <slot :text="message"></slot> </div> </template> <script> export default { data() { return { message: 'Hello from Child' }; } }; </script>
-
生命周期钩子(Lifecycle Hooks)
- 组件的生命周期钩子是指在组件的创建、挂载、更新和销毁过程中会被自动调用的函数。常用的生命周期钩子有:
- created: 组件实例创建完成后调用。
- mounted: 组件挂载到DOM后调用。
- updated: 组件更新后调用。
- destroyed: 组件销毁后调用。
-
export default { created() { console.log('Component created'); }, mounted() { console.log('Component mounted'); }, updated() { console.log('Component updated'); }, destroyed() { console.log('Component destroyed'); } };
- 组件的生命周期钩子是指在组件的创建、挂载、更新和销毁过程中会被自动调用的函数。常用的生命周期钩子有:
-
高级特性
- 动态组件:Vue允许动态地切换组件,可以使用
<component>
标签。 -
<template> <div> <component :is="currentComponent"></component> <button @click="switchComponent">Switch Component</button> </div> </template> <script> import ComponentA from './ComponentA.vue'; import ComponentB from './ComponentB.vue'; export default { data() { return { currentComponent: 'ComponentA' }; }, components: { ComponentA, ComponentB }, methods: { switchComponent() { this.currentComponent = this.currentComponent === 'ComponentA' ? 'ComponentB' : 'ComponentA'; } } }; </script>
-
异步组件:可以按需加载组件,提升应用的性能。
-
export default { components: { 'my-async-component': () => import('./MyAsyncComponent.vue') } };
- 动态组件:Vue允许动态地切换组件,可以使用
4.vue里的一些插件可以怎么做
5.写实现一个request,可以在失败的时候重试,有interval和maxCount参数 : oc
/**
* 带重试功能的请求函数
* @param {string} url - 请求的URL
* @param {object} options - fetch请求的选项对象
* @param {number} interval - 每次重试之间的间隔时间(毫秒)
* @param {number} maxCount - 最大重试次数
* @returns {Promise<Response>} - 返回一个Promise,解析为fetch的Response对象
*/
async function requestWithRetry(url, options, interval, maxCount) {
let attempts = 0; // 记录已尝试的次数
// 当尝试次数小于最大重试次数时,继续尝试
while (attempts < maxCount) {
try {
// 尝试发送请求
const response = await fetch(url, options);
// 如果响应状态不是ok,抛出错误
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
// 请求成功,返回响应结果
return response;
} catch (error) {
attempts++; // 增加尝试次数
console.log(`Attempt ${attempts} failed: ${error.message}`); // 打印错误信息
// 如果达到最大重试次数,抛出错误
if (attempts >= maxCount) {
throw new Error(`Max retries reached: ${error.message}`);
}
// 等待一段时间再重试
await new Promise(resolve => setTimeout(resolve, interval));
}
}
}
// 使用示例
const url = 'https://jsonplaceholder.typicode.com/posts'; // 请求的URL
const options = {
method: 'GET', // 请求方法为GET
headers: {
'Content-Type': 'application/json' // 请求头,指定内容类型为JSON
}
};
const interval = 1000; // 每次重试间隔1秒(1000毫秒)
const maxCount = 3; // 最多重试3次
// 调用带重试功能的请求函数
requestWithRetry(url, options, interval, maxCount)
.then(response => response.json()) // 解析响应结果为JSON
.then(data => console.log(data)) // 打印请求成功后的数据
.catch(error => console.error(error)); // 捕获并打印错误信息