业务场景下请求数量不一致如何优化

111 阅读3分钟

背景

前端应用中,请求网络资源是很常见但消耗也不小。一个网络请求往往包含地址解析、建立连接、数据下载、数据解析等过程,因此我们应当尽可能的节省网络请求,最大程度的提升前端应用的加载速度,提升用户体验。同时,我们也应当尽可能的利用浏览器并行网络请求的机制,将相互独立的请求并行请求,减少用户等待时间。然而,在实际的业务场景中,单次加载时所需要的网络请求数量可能是不同的。本人经过一定的实践后,可能找到了最佳实现的方式,也欢迎大家一起讨论。

并行请求

我们可以直接使用 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]);
        }
    }
}

最佳实践?

目前找到的比较简便的写法,在构造请求队列的时候根据条件放入对应的请求或一个直接 resolvePromise

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),,
    ]);
}