【Effective Web】页面优化

页面优化

页面渲染流程

JavaScript 》 Style 》 Layout 》 Paint 》 Composite

首先js做了一些逻辑,触发了样式变化,style计算好这些变化后,把影响的dom元素进行重新布局(layout),再画到画布中(Paint),最后把这个画布刷新到屏幕上(Composite),形成一帧。

屏幕的分辨率一般是60Hz,也就是一秒要60帧,1000ms/60约等于16.67ms,加上浏览器内核自身运算也要消耗些时间,一帧差不多就10ms,渲染的过程中上面哪一步耗时长了,这一帧耗时变多,帧率就下降,页面看起来就卡。

上面的步骤不一定都会执行,页面优化可以从这些方面考虑,比如:

  • js只做计算,没有增加删除dom或改变css,后面几步就不会执行。
  • style只改了color/background等不需要重新layout的不用执行layout
  • style改了transform属性,在edge不需要layout和Paint

devtool调试

edge浏览器有个devtool工具,点击performance页签,记录一段时间的浏览器操作,关闭记录按钮就会生成这次操作的详细信息

这种有个小红方块的是渲染时间比较长的帧
在这里插入图片描述

取其中一个帧,可以看到是js执行时间比较长
在这里插入图片描述

拆分代码块

既然一个js 代码块执行太久导致卡顿,那能不能把代码拆分?
我们把代码拆分成几个单元task,每个单元控制执行不超过10ms,建立一个Task类来管理这些task,js每次渲染帧时会调用一个函数requestAnimationFrame,接受一个函数,建立一个任务队列。

// Task定义class Task {constructor() {this.tasks = [];}addTask(task) {this.tasks.push(task);}draw() {let that = this; // 这里用that来代替是避免this指向问题window.requestAnimationFrame(function () {let tasks = that.tasks;if (tasks.length) {let task = tasks.shift();task();}window.requestAnimationFrame(function () {that.draw.call(that);});});}}

使用的时候先创建Task实例,调draw初始化,有任务时addTask添加到队尾,执行任务时调shift执行任务

  // 用单例模式控制mapTask只有一个let mapTask = {get: function () {if (!atask) {atask = new Task();atask.draw();}return atask;},add: function (task) {mapTask.get().addTask(task);},};

这里举个例子,模拟执行时间长的函数

  let fullTask = () => {for (let i = 0; i < 5000; i++) {console.log("i :>> ", i);}};

执行时间78.3ms
在这里插入图片描述

把这个函数拆分成很多给子任务去执行

  let subTask = () => {let k = 0;let sub1 = () => {for (let j = 0; j < 100; j++) {k++;console.log("k :>> ", k);}};for (let i = 0; i < 50; i++) {mapTask.add(sub1);}};

在这里插入图片描述
每个sub1函数不超过10ms,这样大大减少函数执行时长。
在这里插入图片描述

补一个全局的对比
拆分前的:
在这里插入图片描述

拆分后的:
在这里插入图片描述

全部的代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><button onclick="fullTask()">fullTask</button><button onclick="subTask()">subTask</button></body>
</html><script>let fullTask = () => {for (let i = 0; i < 5000; i++) {console.log("i :>> ", i);}};class Task {constructor() {this.tasks = [];}addTask(task) {this.tasks.push(task);}draw() {let that = this; // 这里用that来代替是避免this指向问题window.requestAnimationFrame(function () {let tasks = that.tasks;if (tasks.length) {let task = tasks.shift();task();}window.requestAnimationFrame(function () {that.draw.call(that);});});}}let atask = null;// 用单例模式控制mapTask只有一个let mapTask = {get: function () {if (!atask) {atask = new Task();atask.draw();}return atask;},add: function (task) {mapTask.get().addTask(task);},};let subTask = () => {let k = 0;let sub1 = () => {for (let j = 0; j < 100; j++) {k++;console.log("k :>> ", k);}};for (let i = 0; i < 50; i++) {mapTask.add(sub1);}};
</script>

减少渲染堵塞

避免head标签js堵塞

所有放在head标签的css和js文件都会堵塞渲染,应避免在head标签价加载css和js文件。
可以在js文件加上defer,具有 defer 特性的脚本不会阻塞页面。具有 defer 特性的脚本总是要等到 DOM 解析完毕,但在 DOMContentLoaded 事件之前执行。
加上async可以实现异步加载,async和defer的区别主要在加载后的处理,下面举一个例子说明:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>defer</title></head><body></body>
</html><script src="test1.js" onload="test1()" defer></script>
<script src="test2.js" onload="test2()" defer></script><script src="test1.js" onload="test1()" async></script>
<script src="test2.js" onload="test2()" async></script>
// test1.js
var a;
function test1() {a = "一个超长的字符串"; // 大概有几m大小,这里省略alert(a);
}
// test2.js
var b;
function test2() {b = "示例文字";alert(b);
}

这里先后引入两个js文件,分别以defer和async的方式导入,然后在onload回调方法,在页面运行:
defer方式:等所有js文件加载完成后执行,按引入的顺序执行,先执行test1(),再执行test2()
在这里插入图片描述

async方式:同时加载js文件,不同的是先加载完的先执行,test2.js更快一些,先执行test2()
在这里插入图片描述

defer特点是按顺序执行,不阻塞html,async的特点是先到先执行,可能阻塞也可能不阻塞html,可能会导致乱序。

优化图片

响应式图片

img的srcset属性可以做响应式图片,浏览器根据屏幕大小,设备像素比dpr自动加载合适的图片

    <imgsrcset="Andreas-Kremer-800x1200.jpeg 1x, Karen-Pape-1800x1200.webp 2x"alt=""src="Andreas-Kremer-800x1200.jpeg"/>

压缩和缓存

gzip压缩

nginx的一个配置,可以压缩css文件和js文件

server {gzip on;gzip_types text/plain application/javascript text/css
}

使用etag

ETag HTTP 响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web 服务器不需要发送完整的响应。而如果内容发生了变化,使用 ETag 有助于防止资源的同时更新相互覆盖(“空中碰撞”)。

etag就是对文件的一个校验和,第一次访问时,响应头里面返回这个文件的etag,浏览器第二次请求时把etag带上,Nginx根据这个etag和请求的文件的etag做对比,如果相同就返回304,说明无需再次传输请求的内容,也就是说可以使用缓存的内容

在nginx.conf中:

etag on;

升级到HTTP/2

HTTP/2的优点是一个域只需要建立一次TCP连接,使用多路复用,传输多个资源,不用进行资源排队,像chrome使用HTTP/1.1 只能一次传输6个资源,而且HTTP/2兼容HTTP1.1,如果遇到0不支持HTTP/2的浏览器,会自动转为HTTP/1.1
HTTP/2需要nginx1.10.0和openssl1.0.2以上版本,在nginx.conf中:

listen 443 ssl http2;

增加用户体验

加Loading

  1. 在需要加载很长时间的地方增加加载中的效果,缓解用户等待的焦急心情。
  2. 在按钮上加个loading图标,表示正在执行,也可以避免频繁点击。

增加进度条

  1. 在下发比较久的AJAX请求时,可以增加进度条,但是这个进度条是假的,因为普通的AJAX请求只有0%和100%,可以先load到进度条的60%-80%的一个随机位置,等到请求完成后再直接到100%。
  2. 上传文件的进度条,上传文件可以返回上传的进度,这个进度是真的,可以做一个真的进度条。

按钮按下

按钮在点击的时候,要给人一个被按下去的感觉,只要改动两个属性就行。

  button {background-color: #249dff;}button:active {background-color: #3491df;padding-top: 2px;}

记住用户使用习惯

  1. 记住位置,在用户拖动页面后,记录当前位置,然后在用户刷新页面后自动跳到刚才的位置,而不是让用户再重新拖动页面。
  2. 记住输入,用户填写表单后,下次使用的时候可以给他自动填充表单,减少操作。

总结

本文从避免页面卡顿,怎么加快页面打开速度,增强用户体验三方面入手,说明如何对页面进行优化。当然不止以上这些方式,这里只做抛砖引玉。更重要的是要站在使用者的角度去思考问题,这样才能做出用户满意的页面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/783015.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

半导体工艺技术

完整内容点击&#xff1a;【半导体工艺技术】

将jupyter notebook文件导出为pdf(简单有效)

1.打开jupyter notebook笔记&#xff1a; 2.点击file->print Preview 3.在新打开的页面右键打印 4.另存为PDF 5.保存即可 6.pdf效果 &#xff08;可能有少部分图片显示不了&#xff09; 网上也有其他方法&#xff0c;比如将其转换为.tex再转为PDF等&#xff0c;但个人觉…

ubuntu 中安装docker

1 资源地址 进入ubuntu官网下载Ubuntu23.04的版本的镜像 2 安装ubuntu 这里选择再Vmware上安装Ubuntu23.04.6 创建一个虚拟机&#xff0c;下一步下一步 注意虚拟机配置网络桥接&#xff0c;CD/DVD选择本地的镜像地址 开启此虚拟机&#xff0c;下一步下一步等待镜像安装。 3…

数据可视化-ECharts Html项目实战(8)

在之前的文章中&#xff0c;我们学习了如何设置散点图涟漪效果与仪表盘动态指针效果。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢 今天的文章&#xff0c;会…

【c++】类和对象(六)深入了解隐式类型转换

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来到初始化列表&#xff0c;隐式类型转换以及explicit的内容 目录 1.初始化列表1.1构造函数体赋值1.2初始化列表1.2.1隐式类型转换与复制初始化 1.3e…

python基础——文件操作【文件编码、文件的打开与关闭操作、文件读写操作】

&#x1f4dd;前言&#xff1a; 这篇文章主要讲解一下python中对于文件的基础操作&#xff1a; 1&#xff0c;文件编码 2&#xff0c;文件的打开与关闭操作 3&#xff0c;文件读写操作 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;C语言入…

04 | Swoole 源码分析之 epoll 多路复用模块

首发原文链接&#xff1a;Swoole 源码分析之 epoll 多路复用模块 大家好&#xff0c;我是码农先森。 引言 在传统的IO模型中&#xff0c;每个IO操作都需要创建一个单独的线程或进程来处理&#xff0c;这样的操作会导致系统资源的大量消耗和管理开销。 而IO多路复用技术通过…

OceanBase OBCA 数据库认证专员考证视频

培训概述 OceanBase 认证是 OceanBase 官方推出的唯一人才能力认证体系&#xff0c;代表了阿里巴巴及蚂蚁集团官方对考生关于 OceanBase 技术能力的认可&#xff0c;旨在帮助考生更好地学习 OceanBase 数据库产品&#xff0c;早日融入 OceanBase 技术生态体系&#xff0c;通过由…

MYSQL——索引概念索引结构

索引 索引是帮助数据库高效获取数据的排好序的数据结构。 有无索引时&#xff0c;查询的区别 主要区别在于查询速度和系统资源的消耗。 查询速度&#xff1a; 在没有索引的情况下&#xff0c;数据库需要对表中的所有记录进行扫描&#xff0c;以找到符合查询条件的记录&#…

Doris实践——票务平台的实时数仓建设

目录 前言 一、引入 Doris原因 二、基于Doris搭建数据平台 2.1 构建实时数仓 2.2 Flink CDC全库同步 三、基于Doris进行OLAP报表开发 四、未来规划 原文大佬介绍的这篇票务平台的实时数仓建设有借鉴意义&#xff0c;现摘抄下来用作沉淀学习。如有侵权&#xff0c;请告知…

web前端面试题----->VUE

Vue的数据双向绑定是通过Vue的响应式系统实现的。具体原理&#xff1a; 1. Vue会在初始化时对数据对象进行遍历&#xff0c;使用Object.defineProperty方法将每个属性转化为getter、setter。这样在访问或修改数据时&#xff0c;Vue能够监听到数据的变化。 2. 当数据发生变化时…

Java学习31-Java 多线程Thread 线程的创建

多线程的概念&#xff1a; 用户想要一边听歌&#xff0c;一边QQ聊天&#xff0c;一边游戏。要求能并发执行。 program程序&#xff1a; 有特殊功能的一组代码process进程&#xff1a; 正在执行中的program&#xff0c;或者程序program的一次执行过程thread线程&#xff1a;程…

CSS实现元素边框渐变动画

前言&#xff1a; 边框流动动画是一种非常常见的效果&#xff0c;能够让网页看起来更加生动有趣。通过使用 CSS3&#xff0c;我们可以轻松地实现这种动画效果。本文将介绍如何使用 CSS3 实现边框流动效果&#xff0c;下面一起来看看吧。 示例图&#xff1a;边框是动画持续变化的…

前端简历:大学还没毕业,就写2年工作经验,上的啥大学呢?

我看过很多前端简历&#xff0c;不知道是不是被所谓简历专家和面试专家给拐带的&#xff0c;还没毕业就敢写2年工作经验&#xff0c;如果属实&#xff0c;大学上了个啥&#xff1f; 简历每天都能收到几十上百封&#xff0c;对于初级人才招聘&#xff0c;基本上看以下几点。 1、…

CIM搭建实现发送消息的效果

目录 背景过程1、下载代码2、进行配置3、直接启动项目4、打开管理界面5、启动web客户端实例项目6、发送消息 项目使用总结 背景 公司项目有许多需要发送即时消息的场景&#xff0c;之前一直采用的是传统的websocket连接&#xff0c;它会存在掉线严重&#xff0c;不可重连&…

深入理解数据结构(3):栈和队列详解

文章主题&#xff1a;顺序表和链表详解&#x1f331;所属专栏&#xff1a;深入理解数据结构&#x1f4d8;作者简介&#xff1a;更新有关深入理解数据结构知识的博主一枚&#xff0c;记录分享自己对数据结构的深入解读。&#x1f604;个人主页&#xff1a;[₽]的个人主页&#x…

瑞吉外卖实战学习--7、员工信息分页查询

员工信息分页查询 前言1、配置公共分页组件2、创建接口并查看接收的参数3、使用分页构造器并添加查询条件和排序条件4、测试结果 前言 1、配置公共分页组件 package com.example.ruiji_demo.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;…

sharemore少数派提示词或许需要工程,但提问一定需要智慧

Matrix 首页推荐 Matrix 是少数派的写作社区&#xff0c;我们主张分享真实的产品体验&#xff0c;有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章&#xff0c;展示来自用户的最真实的体验和观点。 文章代表作者个人观点&#xff0c;少数派仅对标题和排版略作…

代码随想录算法训练营第二十五天| 216.组合总和III,17.电话号码的字母组合

题目与题解 216.组合总和III 题目链接&#xff1a;216.组合总和III 代码随想录题解&#xff1a;216.组合总和III 视频讲解&#xff1a;和组合问题有啥区别&#xff1f;回溯算法如何剪枝&#xff1f;| LeetCode&#xff1a;216.组合总和III_哔哩哔哩_bilibili 解题思路&#xf…

数据结构和算法:图

图 图&#xff08;graph&#xff09;是一种非线性数据结构&#xff0c;由顶点&#xff08;vertex&#xff09;和边&#xff08;edge&#xff09;组成。可以将图 &#x1d43a; 抽象地表示为一组顶点 &#x1d449; 和一组边 &#x1d438; 的集合。 如果将顶点看作节点&#…