百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

JS基础与高级应用: 性能优化(js性能优化有哪些方法)

toyiye 2024-08-24 00:29 4 浏览 0 评论

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

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

第一步: 从 输入 开始分析

URL 和 URI 的区别

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

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

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

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

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



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 条。



并发优化: 同时发出 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。

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码