背景
前端应用中,请求网络资源是很常见但消耗也不小。一个网络请求往往包含地址解析、建立连接、数据下载、数据解析等过程,因此我们应当尽可能的节省网络请求,最大程度的提升前端应用的加载速度,提升用户体验。同时,我们也应当尽可能的利用浏览器并行网络请求的机制,将相互独立的请求并行请求,减少用户等待时间。然而,在实际的业务场景中,单次加载时所需要的网络请求数量可能是不同的。本人经过一定的实践后,可能找到了最佳实现的方式,也欢迎大家一起讨论。
并行请求
我们可以直接使用 Promise.all() 将多个请求放在一起,当最后一个请求结束时,可以同时得到所有的请求结果。在以下的情况下,我们可以并行进行 3 个请求,最终得到 3 个请求的结果。
// 我们可以用 Promise 模拟请求
function promise(timeout) {
return new Promise((resolve) => {
setTimeout(() => resolve(1), timeout);
});
}
async function app() {
const request1 = promise(1000);
const request2 = promise(1300);
const request3 = promise(1500);
const [result1, result2, result3] = await Promise.all([
request1,
request2,
request3,
]);
}
业务场景
我们假定 request1 在任何时候都需要,其他 2 个请求只有在某些情况下需要进行,这 3 个请求之间是相互独立的,我们希望避免不必要的请求发生。
尝试一
我们可以尝试使用数组来进行管理,我们首先需要根据条件管理请求数组队列,然后需要再次根据条件管理请求结果。如果 requests 很多的话,会产生很多判断的分支,虽然管理请求数组队列并不那么复杂。
async function app() {
const request1 = promise(1000);
const request2 = promise(1300);
const request3 = promise(1500);
const queue = [request1];
const condition2 = false; // 根据实际情况是个不确定的值
const condition3 = false; // 根据实际情况是个不确定的值
if (condition2) {
queue.push(request2);
}
if (condition3) {
queue.push(request3);
}
const results = await Promise.all(queue);
const result1 = results[0]; // 这个是确定的
const result2 = condition2 ? results[1 : undefined; // 略复杂
const result3 = condition2 ? (condition3 ? results[2] : undefined ) : (condition3 ? results[1] : undefined); // 复杂
}
尝试二
我们可以尝试优化上述代码把条件判断提前,虽然这下把请求队列的管理和请求的管理合并在一起了,但是同样无法避免条件判断的复杂性会因为请求的数量指数性上升。
async function app() {
const request1 = promise(1000);
const request2 = promise(1300);
const request3 = promise(1500);
let result1, result2, result3; // 需要提前有个 placeholder
const condition2 = false; // 根据实际情况是个不确定的值
const condition3 = false; // 根据实际情况是个不确定的值
if (condition2) {
if (condition3) {
[result1, result2, result3] = await Promise.all([request1, request2, request3]);
} else {
[result1, result2] = await Promise.all([request1, request2]);
}
} else {
if (condition3) {
[result1, result3] = await Promise.all([request1, request3]);
} else {
[result1] = await Promise.all([request1]);
}
}
}
最佳实践?
目前找到的比较简便的写法,在构造请求队列的时候根据条件放入对应的请求或一个直接 resolve 的 Promise
async function app() {
const request1 = promise(1000);
const request2 = promise(1300);
const request3 = promise(1500);
const condition2 = false; // 根据实际情况是个不确定的值
const condition3 = false; // 根据实际情况是个不确定的值
const [result1, result2, result3] = await Promise.all([
request1,
condition2 ? request2 : Promise.resolve(null),
condition3 ? request3 : Promise.resolve(null),,
]);
}