"前端并发请求优化:提升Web应用性能的高效策略"

97 阅读2分钟

前端控制并发请求,使用Promise 在现代前端开发中,处理大量并发请求是一个常见的需求。如果不加以控制,大量并发请求可能导致服务器压力过大或客户端性能问题。因此,合理控制并发请求数量,确保系统的稳定性和响应能力至关重要。本文将详细探讨如何使用Promise来控制并发请求,以满足实际业务需求。

  1. 使用Promise.all()和Promise.allSettled() 首先,我们可以使用Promise.all()方法来实现并发请求。然而,当请求失败时,Promise.all()会立即失败且无法获取组内其他请求的返回值。为了解决这个问题,可以使用Promise.allSettled()方法,它能确保每个请求都能返回结果,无论成功还是失败。

const requests = [request1(), request2(), request3()]; Promise.allSettled(requests).then(results => { results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(Request ${index + 1} succeeded with result:, result.value); } else { console.log(Request ${index + 1} failed with reason:, result.reason); } }); }); 2. 维护运行池和等待队列 如果存在一个非常耗时的请求,可能会导致后续请求的阻塞,影响整体效率。为了解决这一问题,可以维护一个运行池和一个等待队列。运行池始终保持一定数量的请求并发,当一个请求完成时,从等待队列中取出一个新请求放入运行池中执行。

function sendRequest(requestList, limits, callback) { const pool = new Set(); let index = 0;

const runTask = async () => {
    if (index >= requestList.length) return;
    const request = requestList[index++];
    const promise = request();
    pool.add(promise);
    promise.then(() => {
        pool.delete(promise);
        runTask();
    }).catch(err => {
        console.error('Request failed:', err);
        pool.delete(promise);
        runTask();
    });
};

for (let i = 0; i < limits; i++) {
    runTask();
}

const checkCompletion = setInterval(() => {
    if (pool.size === 0) {
        clearInterval(checkCompletion);
        callback();
    }
}, 100);

} 3. 使用p-limit库 p-limit库是一个优秀的并发限制库,通过简单的代码实现了并发处理功能。p-limit库使用Queue队列来管理并发请求,当队列大小小于最大并发数且队列不为空时,从队列中取出一个请求执行。

const pLimit = require('p-limit');

const limit = pLimit(5);

const input = [ () => fetchSomething('sindresorhus.com '), () => fetchSomething('ava.li '), () => fetchSomething('github.com ') ];

const promises = input.map(fn => limit(fn));

(async () => { const result = await Promise.all(promises); console.log(result); })(); 4. 手动实现并发请求控制 手动实现并发请求控制的方法是创建一个请求队列,并通过设置最大并发数来控制同时进行的请求数量。当一个请求完成时,从队列中取出下一个请求并执行。

function sendRequest(requestList, limits, callback) { const queue = [...requestList]; let activeCount = 0; const results = [];

const next = () => {
    while (activeCount < limits && queue.length > 0) {
        const request = queue.shift();
        activeCount++;
        request().then(result => {
            results.push(result);
            activeCount--;
            next();
        }).catch(err => {
            console.error('Request failed:', err);
            activeCount--;
            next();
        });
    }
    if (activeCount === 0 && queue.length === 0) {
        callback(results);
    }
};

next();

} 5. 处理请求结果和错误重试 在实际应用中,我们还需要处理请求结果和错误重试机制。可以通过增加一个参数来控制请求失败的重试次数。

function sendRequest(requestList, limits, retries, callback) { const queue = [...requestList]; let activeCount = 0; const results = [];

const next = () => {
    while (activeCount < limits && queue.length > 0) {
        const request = queue.shift();
        activeCount++;
        let attempt = 0;
        const executeRequest = () => {
            request().then(result => {
                results.push(result);
                activeCount--;
                next();
            }).catch(err => {
                attempt++;
                if (attempt <= retries) {
                    console.log(`Retrying request... Attempt ${attempt}`);
                    executeRequest();
                } else {
                    console.error('Request failed after retries:', err);
                    activeCount--;
                    next();
                }
            });
        };
        executeRequest();
    }
    if (activeCount === 0 && queue.length === 0) {
        callback(results);
    }
};

next();

}