技术标签: html5 react 前端面试 javascript
初始阶段 -> 加载优化
运行阶段 -> 渲染优化
#####问题分析
结论:所有加载慢的问题最终都可以归纳成两个问题 多 和 大。Tips:还有网速不好和电脑太渣
#####问题讲解
模拟面试对话
Q: 面试官爸爸 A: 你
Q:那既然你已经知道了首页加载慢的几个原因,那我先问你首页加载图片过多怎么处理?
A:减少图片不就完了吗
Q:那我们的首页就是有这么多图片怎么办?
如何分析:看看淘宝怎么解决
A: 可以通过懒加载的方式来减少首屏图片的加载量
Q: 懒加载是什么原理?
如何分析:看看懒加载的库
<img alt="A lazy image" data-src="lazy.jpg">
<------ 滚动到特定位置的时候 ------>
<img alt="A lazy image" src="lazy.jpg" data-src="lazy.jpg">
A: 懒加载原理就是监听滚动条事件,如果(滚动条距离浏览器顶部的高度 === 图片距离顶部的高度),那么就将 data-src 的值赋值到 src 上。
Q: 那假设首页的小图片就是很多,比如有很多个小 ICON 怎么办?
如何分析:还是看看淘宝怎么解决
A: 可以分别使用 iconfont 和雪碧图来处理小图标和小图片
总结:
首页加载图片过多的问题,可以通过以下几种方法解决:
- 通过懒加载的方式处理非首屏的图片
- 对于小图标可以采用 iconfont 的方式解决
- 对于小图片可以采用雪碧图的方式解决
Q: 首页的请求量过多怎么解决?
如何分析:
先通过工具来确定是哪些类型的资源请求过多
通过浏览器的 Network 可以确定首页加载的资源和请求量
requests:请求数量
resources:前端资源总大小
DOMContentLoaded: 浏览器已经完全加载了 HTML, 其他静态资源( JS, CSS, 图片等)并没有下载完毕(能看,不能用)
Load:浏览器已经加载了所有的静态资源(能用了)
通过 converge 来查看代码的使用状况
A: 可以通过减少资源的请求量
Q: 只有通过合并静态资源的方式才能减少资源请求量吗?
如何分析:
除了从资源层面来解决问题,还可以从我们自己写的代码本身来考虑。
对于引入的一些比较大型的第三方库,比如 组件库(antd,element-ui),函数库(lodash)等,务必设定按需加载。Tips: 一般都是用 Babel 插件来实现的
可以通过前端路由懒加载的方式(只限于 SPA 应用)
A: 当然不是,还可以从代码层面的优化,比如说:
1. 如果在项目中引入了比较大型的第三方库,那就可以通过特定的 Babel 插件来进行按需加载
2. 在路由层面也可以使用 React lazy 进行动态路由的加载,从而可以减少首页的 JS 和 CSS 的大小
Q:那我问你为什么 React lazy 可以进行动态路由的加载?
如何分析:先看看使用方式
// 1. 引入 react lazy, 并且使用 import 动态导入组件
import { lazy } from 'react'; // 静态导入
lazy(() => import('./Home')); // 动态导入
// 2. 引入 Suspense 组件,并使用 Suspense 将根组件包裹起来,并使用 fallback props 传入 loading 组件
import { Suspense } from 'react';
// 注意:使用 lazy 加载的组件,必须是 Suspense 子组件,或者孙组件
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
动态导入(dynamic import):当代码运行 import 的时候,再导入组件
import("./math").then(math => {
console.log(math.add(16, 26));
});
// 类似于 fetch,都是返回一个 Promise
fetch("./math").then(math => {
console.log(math.add(16, 26));
});
演示 Webpack 的代码分割
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ghvtVgx5-1622953813865)(./assets/1.png)]
结论:
import(‘xxx’) 返回的是一个 Promise
Webpack 只要遇到了 import(‘xxx’),就会把括号里引入的内容单独打一个包
A: 首先 React lazy 是使用了 dynamic import 的标准,webpack 只要遇到了 dynamic import, 就会把里面引入的内容单独打一个包。
由于 dynamic import 返回的是一个 Promise,所以可以使用 Promise 的状态来做渲染的流程控制。
如果当前 Promise 是 pending 状态,那么就渲染 Loading 组件,如果 Promise 是 resolve 状态那么就渲染动态导入的组件。
总结:
首页的请求量过多,可以通过一些手段来减少资源的请求量,比如:
- 通过 nginx 服务器来做资源文件的合并或者通过 Webpack 等打包工具进行物理打包
- 在代码层面,对于需要引入一些大型第三方库的时候,可以通过特定的 Babel 插件来进行按需加载
- 还有可以使用 React lazy 或其他动态导入方案来进行前端路由层面的动态加载,从而可以减少首页的 JS 和 CSS 的大小
Q: 首页请求的资源(CSS、JS、图片…)过大怎么解决?
A: 把资源变小不就完了吗?
Q: 怎么变小?
A:
/usr/local/etc/nginx
)#####答题思路
对于首页加载慢的问题,一般是由于首页加载资源过多,并且资源过大导致。所以应对的策略就减少资源的数量以及减小资源的大小。
- 对于图片可以懒加载,减小首屏图片加载量。以及对于小图标和小图片和分别使用 iconfont 和 雪碧图来解决,最大程度减少首屏图片数量,从而提升首页渲染性能。
- 对于其他资源可以通过打包(nginx combo 或者 Webpack 打包)来合并资源,并可以通过懒加载路由的方式来减小首页 JS 的加载量
- 减小资源的方式可以通过压缩和混淆加密来减小文件体积,图片则可以使用工具来压缩或者使用 webp 格式。
- 同时可在服务器端开始 gzip 压缩来最大化减少所有文件体积。
前端中最常见资源:HTML、CSS、JS、图片
####2. 优化图片的做法
Q: 好,那你刚刚说可以使用自动化工具对图片进行压缩,你是使用什么工具?
A: 用 熊猫站 不就完了吗?
如何分析
熊猫站:智能压缩 PNG 和 JPG 的一个网站
Q: 那你认为为什么这个工具可以同比例无损压缩?
如何分析
看看熊猫站的描述
通过相似颜色“量化”的技术来减少颜色数量,并且可以将 24 位的 PNG 文件转化成 8位的彩色图片。同时可以将不必要的元数据进行剥离。
–> 翻译成人话
通过减少颜色的数量以及不必要的数据来实现文件压缩
A:通过减少颜色的数量以及不必要的数据来实现文件压缩
Q: 非常 nice,但是这是方式不是有一个问题?难道每当我需要处理图片的时候,就要进入这个网站去上传一下吗?这样不仅仅效率低,还不安全。
A: 熊猫站很佛系的,他们把图片压缩工具 开放 出来了。可以使用 npm 安装开源包,就可以在我们本地进行图片压缩啦。
Q: 那除了这个方式还有什么其他的方式来优化图片吗?
如何分析
对图片进行转码 -> base64 格式
A: 可以使用 Webpack 的 url-loader 进行图片策略配置,将小图转换成 base64 格式,因为 base64 格式的图片的作用是减少资源的数量,但是 base64 格式的图片会增大原有图片的体积
A: 还有一种方式就是使用 webp 格式的图片
如何分析
图片格式有很多种,PNG、JPG、GIF,还有新的 WebP 格式
WebP 的优势:
根据 Google 的测试,同等条件等比例无损压缩后的 WebP 比 PNG 文件少了 26% 的体积。并且图片越多,压缩后的体积优势越明显。
压缩率比较,JPG vs WebP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fv0IZczI-1622953813867)(./assets/2.jpg)]
加载时间比较,JPG vs WebP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2bcji073-1622953813868)(./assets/3.jpg)]
#####答题思路
图片的优化,也是从两个方面来考虑:太多 和 太大。
可以通过懒加载减少图片的请求,或者通过雪碧图来合并图片,以及将小图转化成 base64 的格式,来解决多的问题。
图片大的问题,可以通过自动化压缩工具来压缩图片,或者使用 WebP 格式的图片。
#####问题分析
#####问题讲解
Q: 我问你,怎么使用 Webpack 进行打包优化?
A: 少 和 小
Q: 怎么样少,怎么样小
如何分析
少 -> 使用 Webpack 进行物理打包。
小 -> 使用 Webpack 进行混淆和压缩,所有与 Webpack 优化相关的配置都是在 optimization 这个配置项里管理。
从 webpack 4 开始,会根据你选择的 mode 来执行不同的优化,不过所有的优化还是可以手动配置和重写。
development:不混淆,不压缩,不优化
production:混淆 + 压缩,自动内置优化
结论:只需要将 mode 改成 production 即可
A: 使用 Webpack 对代码进行混淆和压缩,并且可以使用 React lazy 进行拆包,结合路由进行按需加载。
Q: 那这里是不是有个问题?既然你对文件进行拆包处理,那么肯定会造成文件变多,是不是有矛盾?
如何分析
其实不冲突,因为拆包后的文件,不可能同时加载的,所以就不会造成同一时间资源请求过多的请求。
但是要注意打包策略
我们通常会把包,分为两类
第三方包(node_modules 里面的)
自己实现的代码(src 目录里面的)
- 公共的
- 非公共的
所以我们可以把第三方包打一个包,公共的代码打一个包,非公共的代码打一个包。
第三方包:改动频率 – 小
公共代码包:改动频率 – 中
非公共代码包:改动频率 – 高
所以可以将 打包策略 结合 网络缓存 来做优化
对于不需要经常变动的资源(第三方包),可以使用 Cache-Control: max-age=31536000
(缓存一年) 并配合协商缓存 ETag
使用(一旦文件名变动才会下载新的文件)
对于需要频繁变动的资源(代码包),可以使用 Cache-Control: no-cache
并配合 ETag
使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
A: 其实不冲突,因为拆包后的文件,不可能同时加载的,所以就不会造成同一时间资源请求过多的请求。但是可以使用 Webpack 的 optimization.splitChunks 进行打包策略的优化。将 node_modules 单独打包,以及将自己实现的代码也可以分为公共包和非公共包,并且分开打包。
最后还可以结合网络缓存来做加载性能优化。
#####答题思路
Webpack 打包优化,也是从两个方面来考虑:太多 和 太大。
- 可以通过设置 mode = production 来默认实现 Webpack 对代码的混淆和压缩,从而最大程度的减少代码体积
- 使用 Webpack + dynamic import 并结合路由的入口文件做拆包处理。
- 并且可以设定一些打包策略,并配合网络缓存做最终的加载性能优化。
####4. 实现 CDN 加速
为什么 CDN( 解决方案 -> nginx ) 可以实现加速
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2BRya1u4-1622953813869)(./assets/4.jpeg)]
游戏分区:北京一区,上海一区,广东一区…
Tips:CDN 服务器就是在你家门口放一台服务器,把所有的静态资源都同步到你家门口这台服务器上,以后只要你访问这个网站,都直接从这台服务器上下载静态资源。
Http1.1 请求:对于同一个协议、域名、端口,浏览器允许同时打开最多 6个 TCP 连接(最多同时发送 6个请求)
主站 Request URL: https://www.taobao.com/
JS&CSS Request URL: https://g.alicdn.com/??kg/home-2017/1.4.17/lib/style/lazy.css
图片 Request URL: https://img.alicdn.com/tfs/TB1_uT8a5ERMeJjSspiXXbZLFXa-143-59.png
字体 Request URL: https://at.alicdn.com/t/font_403341_n8tj33yn5peng66r.woff
扩展:Http2.0: 引入了多路复用的机制,可以最大化发送请求数量。
CDN 服务器主要是用来放静态资源的服务器,可以用来加速静态资源的下载
CDN 之所以能够加速,是因为会在很多地方都部署 CDN 服务器,如果用户需要下载静态资源,会自动选择最近的节点下载
同时由于 CDN 服务器的地址一般都跟主服务器的地址不同,所以可以破除浏览器对同一个域名发送请求的限制
####1. 渲染十万条数据如何不造成卡顿
为什么渲染很多条数据会造成浏览器卡顿
为什么渲染很多条数据会造成浏览器卡顿
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olQwyv6s-1622953813871)(./assets/5.jpg)]
结论:
- 无论是浏览器中的 DOM 和 BOM,还是 NodeJS,它们都是基于 JavaScript 引擎之上开发出来的
- DOM 和 BOM 的处理最终都是要被转换成 JavaScript 引擎能够处理的数据
- 这个转换的过程很耗时
- 所以在浏览器中最消耗性能的就是操作 DOM
指导原则:尽可能的减少 DOM 的操作
eg:假如有一个需求,我们要在一个页面中 ul 标签里渲染 十万 个 li 标签。
// 插入十万条数据
const total = 100000;
let ul = document.querySelector('ul'); // 拿到 ul
// 懒加载的思路 -- 分段渲染
// 1. 一次渲染一屏的量
const once = 20;
// 2. 全部渲染完需要多少次,循环的时候要用
const loopCount = total / once;
// 3. 已经渲染了多少次
let countHasRender = 0;
function add() {
// 创建虚拟节点,(使用 createDocumentFragment 不会触发渲染)
const fragment = document.createDocumentFragment();
// 循环 20 次
for (let i = 0; i < once; i++) {
const li = document.createElement('li');
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
// 最后把虚拟节点 append 到 ul 上
ul.appendChild(fragment);
// 4. 已渲染的次数 + 1
countHasRender += 1;
loop();
}
// 最重要的部分来了
function loop() {
// 5. 如果还没渲染完,那么就使用 requestAnimationFrame 来继续渲染
if (countHasRender < loopCount) {
// requestAnimationFrame 叫做逐帧渲染
// 类似于 setTimeout(add, 16);
// 帧:一秒钟播放多少张图片,一秒钟播放的图片越多,动画就约流畅
// 1000/60 = 16
window.requestAnimationFrame(add);
}
}
loop();
结论:
- 可以使用 document.createDocumentFragment 创建虚拟节点,从而避免引起没有必要的渲染
- 当所有的 li 都创建完毕后,一次性把虚拟节点里的 li 标签全部渲染出来
- 可以采取分段渲染的方式,比如一次只渲染一屏的数据
- 最后使用 window.requestAnimationFrame 来逐帧渲染
导致浏览器卡顿的原因一般都是操作 DOM 的次数太频繁。
如果想要渲染很多条数据不造成卡顿,那么就一定要尽可能的减少操作 DOM 的次数。
比方说 React 的虚拟 DOM,本质上就是用 JS 数据来模拟真实 DOM树,从而大大减少了操作真是 DOM 的次数。
还有在渲染的时候,可以使用 document.createDocumentFragment 创建虚拟节点,从而避免引起没有必要的渲染
也可以采取分段渲染的方式,最后使用 window.requestAnimationFrame 来逐帧渲染
记住:
在前端中性能优化的点主要分为两个阶段:
初始阶段,主要就是加载方面优化的问题。所有问题的指导原则就两点:
- 尽可能的减少前端资源的数量
- 尽可能的减小前端资源的大小
运行阶段,主要就是渲染方面优化的问题。只要是在浏览器中,所有的问题的指导原则就是:
- 尽可能的减少操作 DOM
文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware
文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停
文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象