Skip to content

Commit

Permalink
feat✨: 前端性能优化方案
Browse files Browse the repository at this point in the history
  • Loading branch information
lxfljw committed Jun 29, 2024
1 parent 30a9bcb commit dcb3f6d
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 0 deletions.
Binary file modified .DS_Store
Binary file not shown.
48 changes: 48 additions & 0 deletions code/findPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const arr = [
{
id: 1,
child: [
{ id: 3 },
{
id: 4,
child: [
{
id: 5,
child: [{ id: 6 }],
},
],
},
],
},
{
id: 2,
child: [
{
id: 7,
},
],
},
];

function findPathById(arr, id) {
let resPath;
function fn(arr, path = []) {
for (const item of arr) {
if (item.id === id) {
path.push(id);
resPath = path;
return;
}
if (item.child) {
path.push(item.id);
fn(item.child, [...path]);
}
}
}
fn(arr);
return resPath;
}

// findPathById(arr, 6);
console.log("findPathById(arr, 6)", findPathById(arr, 6));
console.log("findPathById(arr, 7)", findPathById(arr, 7));
44 changes: 44 additions & 0 deletions code/limit-fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 2 为并发最大数
const limit = pLimit(2);
const inputs = [
limit(() => fetchSomething(1000), "param1"),
limit(() => fetchSomething(2000), "param2"),
limit(() => fetchSomething(3000), "param3"),
];
function fetchSomething(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
}
const time = Date.now();
Promise.all(inputs).then((results) => {
console.log(results);
console.log(Date.now() - time); // 需要打印为 4s。(解释:因为并发数限制为2,第一个和第二个请求并发进行,第三个等待,第一个结束后开始第三个请求。总体时间为4s)
});

// 实现 pLimit 函数?
function pLimit(limit) {
let count = 0;
const list = [];
function schedule() {
if (count < limit && list.length > 0) {
const { cb, resolve, reject, args } = list.shift();
count++;
cb(...args)
.then(resolve)
.catch(reject)
.finally(() => {
count--;
schedule();
});
}
}
return function (cb, ...args) {
return new Promise((resolve, reject) => {
list.push({ cb, args, resolve, reject });
schedule();
});
};
}
8 changes: 8 additions & 0 deletions code/timu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Object.prototype[Symbol.iterator] = function () {
return Object.values(this)[Symbol.iterator]();
};

// 面试题:如何结构?
const [a, b] = { a: 1, b: 2 };

console.log(a, b); // 1,2
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,33 @@ HTTP 协议的请求流程:
在 HTTP/1.1 及更高版本中,可以通过 Keep-Alive 复用连接,减少 TCP 连接的建立和断开。


## HTTP2


在 HTTP 1.1 中,虽然支持 Keep-Alive 复用 TCP,但是每个域名有 6 个 TCP 的限制,所以并发需要比较多的 hack 操作,比如申请多个不同的域名以支持开启更多的 TCP 链接,然后通过服务端的反向代理这些域名到真正的服务器;之后 HTTP2 解决了 HTTP1 的单个 TCP 只能同时处理一个HTTP 请求的问题,HTTP2 使用二进制帧的概念,多个 Frame 组合成 Stream,Stream是TCP上的逻辑传输单元,能做到一个 TCP 多路复用,减少 TCP 的连接,并且支持头部压缩,相比之下做了不小的优化。

但是 HTTP2 也有 TCP 的致命缺点,假设第一个 Stream 上丢失了 Frame,后面 N 个 Stream 即使到达了服务器,也是不能被处理的,TCP 需要等待前面发出的包有回应才能处理后序的包,所以这个是 TCP 本身的头部阻塞问题,没有办法根本解决,并且在弱网环境下,HTTP2 性能比 HTTP1 还要低。

移动时代,如果用户的 IP 时刻变化,就需要频繁的进行 TCP 连接和反复握手。



## HTTP3

我们先来了解一下 TCP 的拥塞控制:

引用自:[HTTP/3正式发布,深入理解HTTP/3协议](https://www.51cto.com/article/713935.html)
- 慢启动: 发送方像接收方发送一个单位的数据, 收到确认后发送2个单位, 然后是4个, 8个依次指数增长, 这个过程中不断试探网络的拥塞程度.
- 避免拥塞: 指数增长到某个限制之后, 指数增长变为线性增长。
- 快速重传: 发送方每一次发送都会设置一个超时计时器, 超时后认为丢失, 需要重发。
- 快速恢复: 在上面快速重传的基础上, 发送方重新发送数据时, 也会启动一个超时定时器, 如果收到确认消息则进入拥塞避免阶段, 如果仍然超时, 则回到慢启动阶段。

HTTP3 做了相当多的根本升级:
- 放弃了 TCP,使用自己内部开发的 QUIC 协议,底层是 UDP
- QIUCK通过递增的 Packet Number,精准计算 RTT(Round Trip Time)
- QUIC 不需要像 TCP 那样,每个三个数据包就要返回ACK,QUIC 最多可以带 256 个 ACK Block,减少数据包重传问题
- 通过 connectId 来保持连接,即使用户切换了 IP,也能继续复用连接

# 参考连接

1. [HTTP/3正式发布,深入理解HTTP/3协议](https://www.51cto.com/article/713935.html)
123 changes: 123 additions & 0 deletions pages/6-前端知识点/3.移动端适配.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# 移动端适配

## 1. 移动端适配方案

- 方案一:使用viewport
- 方案二:使用rem
- 方案三:使用flexible.js
- 方案四:使用postcss-pxtorem


## 2. viewport

viewport是指浏览器的可视区域,它决定了网页的最终显示效果。

viewport的设置方式有两种:

1. meta标签:

```html
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```

2. CSS:

```css
html {
width: device-width;
height: 100%;
}
```


- width: device-width:设置viewport宽度为设备宽度,这样可以保证页面的宽度适应不同设备的屏幕大小。
- initial-scale=1.0:设置初始缩放比例为1.0,这样可以保证页面的初始显示效果。

我们布局时,能使用 vw,vh 去作为单位,这样就可以完美适配不同设备的屏幕大小。


## 3. rem

rem是相对于根元素html的font-size的单位,它可以实现不同设备的适配。

使用rem的步骤:

1. 设置根元素html的font-size:

```js
const $html = document.querySelector('html');
$html.style.fontSize = $html.clientWidth / 10 + 'px';
```


2. 利用rem单位来设置元素的font-size:

```css
.item {
font-size: 1.6rem;
}
```

## 4. flexible 方案

flexible 方案的原理是指定设计稿的宽度,然后根据 dpr 进行缩放,以达到适配不同屏幕的效果。

假设设计稿宽度为 750px,我们可以设置如下代码:


在 HTML 的 head 标签里配置 meta 如下: `<meta name="viewport" content="width={设计稿宽度}, initial-scale={屏幕逻辑像素宽度/设计稿宽度}" > `

```js
const width = 750;
const dpr = window.devicePixelRatio || 1;
const scale = window.innerWidth / width;

let meta = document.querySelector('meta[name="viewport"]');
const content = `width=${width}, initial-scale=${scale} user-scalable=no`
if (!meta) {
meta = document.createElement('meta');
meta.setAttribute('name', 'viewport')
document.head.appendChild(meta);
}
meta.setAttribute('content', content);


```
那么我们就可以在项目里面愉快的使用 px 啦,并且不需要任何的单位转换。

## 5. postcss-pxtorem

postcss-pxtorem是一个PostCSS插件,它可以将px单位转换为rem单位,实现不同设备的适配。

使用postcss-pxtorem的步骤:

1. 安装postcss-pxtorem:

```
npm install postcss-pxtorem --save-dev
```

2. 在postcss.config.js中配置postcss-pxtorem:

```js
module.exports = {
plugins: [
require('postcss-pxtorem')({
rootValue: 16, // 1rem = 16px
propList: ['*']
})
]
}
```

3. 在需要适配的元素的样式中使用rem单位:

```css
.container {
font-size: 1.6rem;
}
```

## 6. 总结

移动端适配方案有很多,每种方案都有其优缺点,根据项目的实际情况选择适合的方案即可。
Loading

0 comments on commit dcb3f6d

Please sign in to comment.