小册
这是我整理的学习资料,非常系统和完善,欢迎一起学习
背景
最近海外应用有某些用户反馈,打开页面比较卡顿,后来针对这个问题做了层优化
问题
这里我们用微信好友列表
为例子,因为列表功能比较常见,详细分析下常见项目存在的一些问题,以及如何优化
通常我们的项目中都是有列表
这种场景,然后点击列表里面的具体item
,就去到具体的详情页
我们可能是这么处理
<List>
{
list.map((item)=><ListItem id={Item.useId}/>)
}
</List>
然后我们点击好友列表进入具体的详情页根据useId
再去拿具体的信息
getUserInfoById(id)
预加载
但是这里就会存在一个,进入详情页
的时候,打开会慢,所以这里一般会先做数据预加载
,也就是在好友列表的时候
我就想拿到这个详情页数据
,这时候我们可能这么处理
一次性返回数据
<List>
{
list.map((item)=><ListItem detail={Item.detail}/>)
}
</List>
后端支持在好友列表的时候同时返回具体的detail
信息,这样就不用去走一次getUserInfoById(id)
,但是这里也会存在一个问题,好友列表这个接口太冗余,而且数据量太大,打开页面的时候也会出现加载慢的场景
,所以这个策略也只能针对数据量较小的情况采取
预加载getUserInfoById接口
那么干脆一点,我们请求完好友接口后,再根据用户Id,在App下偷偷请求getUserInfoById
接口
getUserInfoById(1)
getUserInfoById(2)
getUserInfoById(3)
...
````
这样就会出现一个问题,后端服务可能扛不住我们这样频繁的请求,所以有什么办法解决呢?那就是`请求合并`,`将多个重复请求(参数不一样),合并成一个,也就是将参数合并`
## 请求合并
const fetchUserInfoBatched = createBatchedRequest<string, UserBaseInfo>(
async (userIds) => {
const { data } = await request.post('/api/user/list', {
userIds,
});
return data;
},
500 // 设置延迟时间为500毫秒
);
// 使用示例
async function getUserInfo() {
const user1 = await fetchUserInfoBatched(1);
const user2 = await fetchUserInfoBatched(2);
const user3 = await fetchUserInfoBatched(3);
console.log(user1, user2, user3);
}
getUserInfo();
### createBatchedRequest
interface BatchRequestItem<T, R> {
params: T;
resolve: (r: R) => void;
reject: (reason: unknown) => void;
}
/**
- 创建批量请求的函数
- 在一定延迟时间内的所有请求都会被合并提交并批量发送
- @param batchFunction 合并后的请求函数
- @param delay 延迟时间,以毫秒为单位
*/
export function createBatchedRequest<T, R>(
batchFunction: (batchParams: T[]) => Promise<R[]>,
delay = 200
): (params: T) => Promise<R> {
const batchQueue: BatchRequestItem<T, R>[] = [];
let isBatching = false;
let timer: NodeJS.Timeout | null = null;
async function executeBatchedRequest() {
if (isBatching) return;
isBatching = true;
const itemsToBatch = [...batchQueue];
batchQueue.length = 0;
try {
const batchedResult = await batchFunction(itemsToBatch.map((item) => item.params));
itemsToBatch.forEach((item, index) => {
item.resolve(batchedResult[index]);
});
} catch (error) {
itemsToBatch.forEach((item) => {
item.reject(error);
});
} finally {
isBatching = false;
}
}
return (params: T): Promise<R> => {
return new Promise<R>((resolve, reject) => {
batchQueue.push({
params,
resolve,
reject,
});
// Execute the batched request after the specified delay
if (!timer) {
timer = setTimeout(() => {
executeBatchedRequest();
timer = null;
}, delay);
}
});
};
}
* **批量请求管理**: `createBatchedRequest` 函数用于管理批量请求,它可以将多个独立的请求合并成一个批量请求,以减少不必要的网络请求次数。
* **参数说明**:
* `batchFunction` 参数是一个函数,接受一个数组 `batchParams` 作为参数,返回一个 Promise,用于处理合并后的请求并返回结果。
* `delay` 参数表示延迟时间,以毫秒为单位。在指定的延迟时间内,所有的请求会被收集起来,然后一次性发送给 `batchFunction` 处理。
* **请求队列**: 函数内部维护一个请求队列 `batchQueue`,用于存储待合并的请求项。每个请求项包含了请求的参数、成功回调函数 `resolve` 和失败回调函数 `reject`。
* **执行批量请求**:
* 当有请求调用返回的函数时,它会将请求参数和相应的回调函数添加到请求队列 `batchQueue` 中。
* 使用定时器控制,在指定的延迟时间后,会执行 `executeBatchedRequest` 函数。
* `executeBatchedRequest` 函数会检查是否已经有批量请求正在处理(`isBatching` 标志),如果有,则不进行处理,直到当前批量请求完成。
* 如果没有正在处理的批量请求,它会取出请求队列中的所有请求项,合并参数后调用 `batchFunction` 处理请求。
* 成功或失败后,会分别调用请求项中的 `resolve` 或 `reject` 回调函数,将结果返回给每个独立的请求。
## 面试
> 最近整理了一套面试小册,有`在线版和离线版本`
离线版本效果如下,可添加微信`linwu-hi`获取,阅读效果非常不错
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/886db51df5a64001bbaf66c2dcf7884a~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=480\&h=480\&e=png\&b=faf7f7)
![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ac45d166a77942df95bbb0552d1b8208~tplv-k3u1fbpfcp-jj-mark:1200:0:0:0:q75.avis)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。