JS基础与高级应用: 性能优化

news2024/11/15 21:39:07

在现代Web开发中,性能优化已成为前端工程师必须掌握的核心技能之一。本文从URL输入到页面加载完成的全过程出发,深入分析了HTTP协议的演进、域名解析、代码层面性能优化以及编译与渲染的最佳实践。通过节流、防抖、重复请求合并等具体技术手段,全面提升Web应用的性能表现。本文不仅涵盖了理论知识,还提供了实用的代码示例,帮助读者在实际项目中快速应用这些优化策略。

一、从输入 URL 到页面加载完成都做了什么?

第一步: 从 输入 开始分析

URL 和 URI 的区别

URL: 资源定位符 | URI: 资源标识符 | www.baidu.com - http 协议

http 和 tcp 之间有什么关联和区别?

http 属于应用层协议, tcp 属于传输层协议

关联: http 是基于 tcp 实现连接的。udp 无连接、传输速度快、会丢包。

http 是如何建立连接的? 三次握手和四次挥手

img

HTTP 面向连接, 安全。但是传输速率相较低于 UDP , 每次请求前都需要建立连接。

优化方向: 回合制(session) 多路复用 | 压缩头部空间 | 合并请求-长连接

优化点: http1.0 http1.1 http2.0

HTTP1.0 存在的问题:

  1. 没有办法复用连接 | 1.1 复用连接 (持久连接, connection: keep-alive)
  2. 对头阻塞问题 (Head-of-Line Blocking,简称 HOL 阻塞) (下一个请求必须在前一个请求到达之后才可以进行); 1.1 => pipelining 解决对头阻塞问题

都是解决传输效率问题

HTTP 1.1 => 2.0: 2.0 解决的问题

  1. 头部空间: 协议层消除头部重复部分,利用算法对头信息压缩整合 ( 头部信息索引表 )。
  2. 1.0/1.1 纯文本格式 | 2.0 二进制优化, HTTP2.0 都是用二进制进行传输, 帧的形式。=> 多路复用(复用通路, 无并发限制)

HTTPS => HTTP + SSL协议

优化: 安全性建立导致网络请求加载时间延长。合并请求-长连接

如何使用 HTTP 2.0 ?

第二步: 解析域名

地址转换成 IP: www.baidu.com => xxx.xxx.xxx.xxx | ARP 协议

IP 转成网址: RARP 协议


什么是 HOST? 如何切换 HOST? => 寻址

浏览器的缓存映射 → 系统缓存映射 → 路由器缓存映射 → 运营商缓存映射 → 根服务器

/etc/hosts localhost 127.0.0.1

实际静态文件存放: 机房、云服务站点 => 大流量问题 =>

配置多个 IP 地址、LB负载均衡、云服务

CDN 内容分发网络

缓存机制: 各级缓存 => 浏览器缓存 (304) - 强缓存(expire cache-control) / 协商缓存 last-modify、etag 找服务端进行验证是否需要缓存。

寻址、缓存

········································································································································································

二、代码层面性能优化

并发控制 QPS

  1. 浏览器请求上限 - 最大同时请求 6 条。

img

并发优化: 同时发出 20 条请求,但是由于服务或者业务需求, 我们的性能只能同时处理 3 个, 怎么去做?

分析:

输入: 参数 max - 最大的同时处理量

存储: reqpool - 并发池 (实时更新, 出去一个进来一个)

思路: 执行且回调, 实时加入添加。 执行 => 回调 => 塞入 => 返回 (循环)

js复制代码    class limitPromise {
        constructor(max){
            // 异步"并发"上限
            this._max =  max || 6 
            // 当前正在执行的任务数量 - 非满载场景
            this._count = 0
            // 等待执行的任务队列
            this._taskQueue = []
            // 实例 单例模式

        }
        // 执行的主入口
        // caller 执行的请求
        run(caller) {
            // 主入口
            // 输入外部要添加的
            // 输出返回队列处理的 promise
            return new Promise((resolve, reject)=>{
                // 创建处理任务
                const task = this._createTask(caller, resolve, reject)
                // 当前队列是否拿到上限
                 if(this._count >= this._max){
                     // 超过最大数量, 不去执行, 放入待执行队列中
                     this._taskQueue.push(task)
                 } else {
                     task()
                 }
            })
        }
        _createTask(caller, resolve, reject){
            return () => {
                caller().then(res =>{
                    resolve(res)
                }).catch(err=>{
                    reject(res)
                }).finally(()=>{
                    this._count--
                    if(this._taskQueue.length){
                        const task = this._taskQueue.shift()
                        task()
                    }
                })
                this._count++
            }
        }
        static instance = null
        static getInstance(max){
            if(!this.instance){
                this.instance = new limitPromise(max)
            }
            return this.instance
        }
    }

节流

js复制代码    function throttle(func, wait) {
      let timeout = null;
      let lastExecution = 0;

      return function (...args) {
        const context = this;
        const now = Date.now();

        if (lastExecution && now < lastExecution + wait) {
          clearTimeout(timeout);
          timeout = setTimeout(() => {
            lastExecution = now;
            func.apply(context, args);
          }, wait - (now - lastExecution));
        } else {
          lastExecution = now;
          func.apply(context, args);
        }
      };
    }

    function handleResize() {
      console.log('Resize event triggered at', new Date().toLocaleTimeString());
    }

    // 创建一个节流函数,最多每1秒执行一次
    const throttledResize = throttle(handleResize, 1000);

    // 监听窗口调整大小事件
    window.addEventListener('resize', throttledResize);

防抖

防抖(Debounce)是指在事件被触发后,等待一段时间再去执行函数。如果在等待时间内事件再次被触发,则重新开始计时。防抖的常见应用场景包括搜索框输入、窗口调整大小、按钮点击等需要防止频繁触发的情况。

防抖函数可以通过 setTimeoutclearTimeout 来实现。以下是一个通用的防抖函数实现:

js复制代码    function debounce(func, wait) {
      let timeout;

      return function (...args) {
        const context = this;

        clearTimeout(timeout);
        timeout = setTimeout(() => {
          func.apply(context, args);
        }, wait);
      };
    }

    function handleInput() {
      console.log('Input event triggered at', new Date().toLocaleTimeString());
    }

    // 创建一个防抖函数,只有在最后一次输入后等待1秒才执行
    const debouncedInput = debounce(handleInput, 1000);

    // 监听输入事件
    const inputElement = document.querySelector('input');
    inputElement.addEventListener('input', debouncedInput);

扩展功能:立即执行选项

有时我们希望在事件触发后立即执行一次函数,并在等待时间内不再执行。可以通过增加一个 immediate 参数来实现:

js复制代码    function debounce(func, wait, immediate) {
      let timeout;

      return function (...args) {
        const context = this;
        const callNow = immediate && !timeout;

        clearTimeout(timeout);
        timeout = setTimeout(() => {
          timeout = null;
          if (!immediate) func.apply(context, args);
        }, wait);

        if (callNow) func.apply(context, args);
      };
    }

<!---->

    function handleInput() {
      console.log('Input event triggered at', new Date().toLocaleTimeString());
    }

    // 创建一个防抖函数,在第一次输入时立即执行,之后等待1秒再执行
    const debouncedInput = debounce(handleInput, 1000, true);

    // 监听输入事件
    const inputElement = document.querySelector('input');
    inputElement.addEventListener('input', debouncedInput);

重复请求的合并

三、编译和渲染优化

打包优化 => 压缩、分割、按需加载、异步加载 => 工程化

渲染优化 => 重排和重绘 => 根据浏览器原理避免

线程阻塞 => JS 后置

内存分配: 即时释放

  1. 对象原则: 层级宜平不宜深, 尽量使用深拷贝(局部), 避免循环利用。
js复制代码<!---->

    function foo(){
        course = '' // 永远不会释放
        this.course = ''
    }
    foo()

    const timeoutId = setTimeout(()=>{}, 1000) // 定时器线程独立于JS线程
    clearTimeout(timeoutId); // 清除定时器

    function course{
        const c = 'xxx'
        return {
            c
        }
    }
    const tmp =course()

    tmp = undefined // 销毁
  1. JS mark & sweep

mark 触达标记: 能够被访问到, 标记; 没有再能访问的 sweep。

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

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

相关文章

esp32s3-gc9a01-lvgl

前言 近期做了一个项目是使用esp32s3 准亿科技的TFT屏幕 该屏幕使用的驱动IC为:GC9A01 通讯方式是:4线SPI , 三线spi和四线SPI区别在于:是否使用D/C信号线 开发LCD屏幕驱动, 可以参考乐鑫官网LCD显示屏指南 SPI 一共有4种工作模式. 根据接线 , 驱动方式的不同. 可分3 , …

【ARM Cache 及 MMU 系列文章 1.4 -- 如何判断 L3 Cache 是否实现?】

文章目录 Cluster Configuration Register代码实现什么是Single-Threaded Core?什么是PE(Processor Execution units)?Single-Threaded Core与PE的关系对比多线程(Multithreading)Cluster Configuration Register 同 L2 Cache 判断方法类似,ARMv9 中也提供了一个自定义…

程序设计实践--3

递推 一只小蜜蜂 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房&#xff0c;不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。其中&#xff0c;蜂房的结构如图所示。 输入描述 输入数据的第一行是一个整数N(1<n<1,000,000),表示测试实例的个数&#xff0c;然…

我的网络安全之路——一场诗意的邂逅

文章来源&#xff5c;MS08067 安全实验室 本文作者&#xff1a;tuooo 我的网络安全之路 一场诗意的邂逅 童年的星光中&#xff0c;我仰望着璀璨的荧屏&#xff0c;心怀对未知机器世界的浩瀚与好奇。那时的我&#xff0c;每每想到各种游戏的破解版本与工具&#xff0c;便会被技术…

在欧拉系统中搭建万里数据库MGR集群(图文详解)

在信创和国产化的大趋势下&#xff0c;将各个中间件进行国产化替换是当前非常重要的任务之一。下面将介绍如何在国产化欧拉系统中安装国产万里数据库。 0.MGR简介 MGR&#xff08;MySQL Group Replication&#xff09;&#xff1a;是MySQL官方提供的一种高可用性和容错性解决…

【java计算机毕设】智慧图书管理系统javaweb MySQL springboot vue html maven送文档

1项目功能截图 【java计算机毕业设计分享】 智慧图书管理系统 Java SpringBoot vue HTML MySQL idea送文档 2项目介绍 系统功能&#xff1a; 智慧图书管理系统包括管理员和读者两种角色。 管理员的功能包括在个人中心修改个人信息和密码&#xff0c;基础数据管理模块包含读者类…

哪款桌面便签软件功能全面且用户评价高?

在日常生活中&#xff0c;便签软件已成为我们不可或缺的小助手。想象一下&#xff0c;在工作或学习时&#xff0c;你能够随时在桌面上看到自己的任务事项&#xff0c;这无疑会大大提高你的效率。便签软件不仅能帮助我们记录重要事项&#xff0c;还能提醒我们按时完成各项任务&a…

IDEA:配置Golang的开发环境及异常

1、下载&安装 进入GO的官网下载对应的GO 我们可以下载安装版&#xff0c;不过本人习惯下载解压版&#xff0c;这个因个人而异 2、配置环境变量 GOBIN : %GOROOT%\bin GOPATH : D:\MyGo 工作区间 GOROOT : D:\Program Files\Go GOJDK地址PATH: %GOBIN% ; %GOROOT%\bin ; …

如何进行考试成绩分析

一、为什么要对考试成绩进行分析&#xff1f; 考试成绩进行分析是一项重要的工作&#xff0c;可以为学生、教师和学校提供有效的学习评价和支持&#xff0c;同时也可以为教学改进和提高教学质量提供有力的支持和指导。对考试成绩进行分析有以下几个原因&#xff1a; 1.了解学生…

液化天然气巡检机器人:LNG 行业的创新守护者

在当今能源领域&#xff0c;液化天然气&#xff08;LNG&#xff09;作为一种清洁、高效的能源正扮演着越来越重要的角色。然而&#xff0c;LNG的生产、存储和运输都面临着高温高压、易燃易爆等巨大风险。为确保安全运营和高效管理&#xff0c;液化天然气行业迫切需要一种创新的…

电压是如何产生的

学过初中物理的人都知道&#xff0c;电源可以产生电压&#xff0c;电子们在电源电压的驱动下&#xff0c;产生定向移动形成电流。电流具有能量&#xff0c;人类学会了利用这股能量&#xff0c;从此科技突飞猛进。然而大部分教材都是从宏观的角度去描述电压这个概念&#xff0c;…

Keil MDK 下载安装相对应CPU的Software Packs

要下载MDK ARM的Software Packs&#xff0c;您可以按照以下步骤进行&#xff0c;这些步骤结合了参考文章中的信息并进行了适当的归纳和整理&#xff1a; 1. 访问Keil官网 打开浏览器&#xff0c;访问Keil的官方网站&#xff1a;www.keil.arm.com。 2. 进入Software Packs下载…

PDF操作工具

PDF的转换、编辑、删除、文本识别、添加水印等等各种操作用的越来越多&#xff0c;相信很多朋友都有WPS等软件的会员、可是更多的朋友是没开通WPS等软件的会员的&#xff0c;那么怎么办呢&#xff0c;给你们推荐一款pdf操作的工具。 PDF24 Creator是一款免费且流行的 PDF 解决…

服务器制作RAID磁盘阵列并管理

1. 规划节点 主机规划 IP主机名节点192.168.100.10localhost控制节点 2. 基础准备 使用VMWare Workstation软件安装CentOS 7.2操作系统&#xff0c;镜像使用提供的 CentOS-7-x86_64-DVD-1511.iso&#xff0c;并添加4块20 GB硬盘。YUM源使用提供的 mdadm_yum文件夹。 1. 创…

探索工厂智能制造解决方案的革新与应用

随着工业4.0时代的到来&#xff0c;工厂智能制造解决方案正在以前所未有的速度和规模改变着传统制造业的面貌。从自动化生产到智能化管理&#xff0c;工厂智能制造解决方案正在为制造企业带来前所未有的效率提升和竞争优势。本文将深入探讨工厂智能制造解决方案的革新与应用&am…

Error:Kotlin: Module was compiled with an incompatible version of Kotlin.

一、问题&#xff1a;运行spring boot项目时&#xff0c;idea报出错误&#xff1a;时提示报错如下图&#xff1a; 错误代码&#xff1a; Error:Kotlin: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected …

Springboot 整合 Flowable(一):使用 flowable-UI 绘制流程图

目录 一、Flowable简介 二、Flowable 与 Activiti 的区别 三、流程图的绘制&#xff08;以员工请假流程图为例&#xff09; 1、下载 flowable 的压缩包&#xff1a; 2、启动包中的 tomcat 3、登录页面 4、绘制结束&#xff0c;导出 bpmn20.xml文件 一、Flowable简介 Fl…

Linux C语言:指针和二维数组

一、一级指针和二维数组 二维数组的元素连续存储&#xff0c;按行优先存 二、数组指针和二维数组 1、二维数组名的理解 行指针&#xff08;数组指针&#xff09;存储行地址的指针变量&#xff0c;叫做行指针变量。形式如下&#xff1a; <数据类型> (*<指针变量名>…

Java内存图相关概念

内存图 1.内存:可以理解"内存条",任何程序,软件运行起来都会在内存中运行,占用内存,在java的世界中,将内存分为了5大块2.分为哪5大块栈(重点)(Stack)主要运行方法,方法的运行都会去栈内存中运行,运行完毕之后,需要"弹栈",腾空间堆(重点):(Heap)每new一次,…

Java面试题--JVM大厂篇之深入了解Java虚拟机(JVM):工作机制与优化策略

引言&#xff1a; Java虚拟机&#xff08;Java Virtual Machine&#xff0c;简称JVM&#xff09;是Java程序员绕不开的主题。作为Java语言的执行平台&#xff0c;JVM不仅为Java程序提供了平台无关性&#xff0c;还承担了内存管理、线程管理和垃圾回收等复杂任务。了解JVM的工作…