【Effective Web】页面优化

news2024/10/7 8:25:45

页面优化

页面渲染流程

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自动加载合适的图片

    <img
      srcset="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.coloradmin.cn/o/1560923.html

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

相关文章

OpenAI 展示音频模型 Voice Engine;清明节前 AI 复活亲人成热门生意丨RTE 开发者日报 Vol.175

开发者朋友们大家好&#xff1a; 这里是「RTE 开发者日报」&#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…

逆向分析之antibot

现在太卷了&#xff0c;没资源&#xff0c;很难接到好活&#xff0c;今天群里看到个单子&#xff0c;分析了下能做&#xff0c;结果忙活了一小会&#xff0c;幸好问了下&#xff0c;人家同时有多个人再做&#xff0c;直接就拒绝再继续了。就这次忘了收定金了&#xff0c;所以原…

Centos7 elasticsearch-7.7.0 集群搭建,启用x-pack验证 Kibana7.4用户管理

前言 Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心&#xff0c;它集中存储您的数据&#xff0c;帮助您发现意料之中以及意料之外的情况。 环境准备 软件 …

【机器学习】数据探索---python主要的探索函数

在上一篇博客【机器学习】数据探索(Data Exploration)—数据质量和数据特征分析中&#xff0c;我们深入探讨了数据预处理的重要性&#xff0c;并介绍了诸如插值、数据归一化和主成分分析等关键技术。这些方法有助于我们清理数据中的噪声、消除异常值&#xff0c;以及降低数据的…

App.vue触发axios报错及解决方案

App.vue触发axios报错及解决方案 修改根目录下vue.config.js文件 module.exports {publicPath: ./,assetsDir: assets,configureWebpack: {devServer: {client: {overlay: false}}} }重新npm run dev 搞定

平台产品线 | 高频问题更新(2024.04.01)

平台产品线 | 高频问题更新(2024.04.01) 一、SuperMap iDesktopX 问题1&#xff1a;麻烦问一下&#xff0c;我有一个数据&#xff0c;想实现符号与标注记的最小显示级别不一样&#xff0c;如1级测站的符号第1级开始显示&#xff0c;但1级测站的注记从第2级才开始显示&#xf…

图片压缩到100k以内?快速压缩图片大小的方法

当您想要分享照片到社交媒体平台时&#xff0c;平台可能有上传文件大小的限制。您可能需要将照片压缩到符合平台要求的大小范围内&#xff0c;以便成功上传和分享照片&#xff0c;或者如果您的设备存储空间有限&#xff0c;您可能需要将照片压缩到较小的文件大小&#xff0c;以…

P1803 凌乱的yyy

凌乱的yyy / 线段覆盖 题目背景 快 noip 了&#xff0c;yyy 很紧张&#xff01; 题目描述 现在各大 oj 上有 n n n 个比赛&#xff0c;每个比赛的开始、结束的时间点是知道的。 yyy 认为&#xff0c;参加越多的比赛&#xff0c;noip 就能考的越好&#xff08;假的&#x…

RUST使用crates.io上的依赖完整教程

1.打开crates.io 2.搜索要使用的依赖,如rand 点击包名,进入包详情页面: 添加依赖方法有两种 1.使用cargo命令 2.直接修改Cargo.toml 使用cargo命令操作如下: 在工程目录执行如下命令: cargo add rand 执行完成后如自动向Cargo.toml中添加依赖如下: 手动修改Cargo.toml是…

CS224N第一课作业--词向量与共现矩阵

文章目录 Word Vectors1. import repos2. Read corpus and calculate co-occurrence matrices2-1 read_corpus2-2 vocabulary2-3 co occurrence matrices2-4. dimensionality reduction完整性检查 3. Prediction-Based Word Vectors余弦相似度 Word Vectors 1. import repos …

计算机网络——33多点访问协议

多点访问协议 多路访问链路和协议 两种类型的链路&#xff08;一个子网内部链路连接形式&#xff09; 点对点 拨号访问的PPP以太网交换机和主机之间的点对点链路 广播 传统以太网HFC上行链路802.11无线局域网 多路访问协议 单个共享的广播型链路 2个过更多结点同时传送&am…

使用pillow创建动态图形验证码

使用pillow创建动态图形验证码 #安装pillow模块&#xff1a;pip3 install pillow from PIL import Image,ImageDraw,ImageFont import random import stringdef id_code(width,height,bit,font_file,font_size):"""功能&#xff1a;生成随机图片验证码:param w…

Linux基本指令篇

在前边&#xff0c;我们已经了解过了Linux操作系统的发展和应用&#xff0c;从该篇起&#xff0c;就正式进入对Linux的学习。 今天我们就来在Xshell上远程登录我们的云服务器。首先我们要知道自己云服务器的公网ip&#xff0c;然后修改一下密码。 点击跳转 修改完密码之后我们…

项目级AIMS手术麻醉信息系统源码,C#手麻系统源码,应用案例+演示

手术麻醉信息系统可以实现手术室监护仪、麻醉机、呼吸机、输液泵等设备输出数据的自动采集&#xff0c;采集的数据能据如实准确地反映患者生命体征参数的变化&#xff0c;并实现信息高度共享&#xff0c;根据采集结果&#xff0c;综合其他患者数据&#xff0c;自动生成手术麻醉…

U8二次开发-钉钉集成

钉钉开放平台作为企业沟通和协作的重要工具,其技术的每一次迭代都为企业带来了新的机遇和挑战。随着企业对于高效沟通和智能化管理的需求日益增长,钉钉平台的SDK更新显得尤为重要。把传统的U8与钉钉平台集成,可以有效的将业务功能和角色进行前移,打破应用系统二八原则,即8…

第三方系统自动登录BBS For Discuz! X3.4/X3.5

apache安装 service apache2 restart PHP安装 php.info php.ini mysql安装 Discuz! X3.4/X3.5安装 跳转BBS 传参 写入BBS 登录BBS

一文教会女朋友学会日常Git使用!Git知识总结

文章目录 一文教会女朋友学会日常Git使用&#xff01;Git知识总结一、git基本知识了解1.git简介2.git区域了解3.git常用命令 二、常用工作场景1.克隆远程仓库&#xff0c;把仓库代码拉到本地2.推送代码到远程仓库&#xff08;1&#xff09;本地代码和远程仓库版本相同&#xff…

GCNet: 非局部网络与挤压-激励网络的融合与超越

摘要 非局部网络&#xff08;NLNet&#xff09;通过为每个查询位置聚合特定于查询的全局上下文&#xff0c;为捕获长距离依赖关系提供了一个开创性的方法。然而&#xff0c;经过严格的实证分析&#xff0c;我们发现非局部网络所建模的全局上下文在图像中的不同查询位置几乎相同…

分享 5 个提高技术领导力的技巧

技术领导力于很多人而言都是谜一般的存在。有观点认为&#xff0c;实战经验丰富的资深开发最终只有成为技术管理者才能继续成长。从某些方面来看&#xff0c;这可能是对的&#xff0c;但考虑到公司结构和规章制度等&#xff0c;想要完成从「个人贡献者」到「技术管理者」的跨越…

ModuleNotFoundError: No module named ‘utils.utils pytorch项目报错

首先呢会报错是因为引入的问题 代码是这样的但是sys.path.append的功能仅限当前的目录 sys.path.append("..") from utils.utils import MyDataset, validate, show_confMat应该加下面的文件路径 sys.path.append("..") from Code.utils.utils import My…