问题
现有 http://ip/ping
接口, 有一堆 ip 地址列表,并发数是 10,请用最快的时间找出 rtt 最少的 ip 地址。
思路
- 并发请求 10个 为 一组,取最快的一个, 然后就取消其他请求,记录下这个ip地址和 rtt
- 如果组内的所有请求比之前记录的 rtt 还慢,则直接取消 fetch
- 如果组内的所有请求比之前记录的 rtt 还快,则记录下这个 ip 地址和 rtt
解决方案
/**
* 找到最快rtt的ip地址
* @param {Array<string>} ips
* @param {number} parellel
*/
async function findShortestRttIp(ips, parellel = 10) {
const chunks = splitChunks(ips);
const result = {
rtt: Infinity,
ip: '',
};
for(const chunk of chunks) {
const pingResult = await race(chunk, result.rtt);
if (pingResult) {
result.rtt = pingResult.rtt;
result.ip = pingResult.ip;
}
}
return result.ip;
}
function splitChunks(ips, parellel = 10) {
const chunks = [];
for(let i = 0; i < ips.length; i += parellel) {
chunks.push(ips.slice(i, i + parellel));
}
return chunks;
}
function race(ips, mininmalRtt) {
return new Promise((resolve) => {
const controller = new AbortController();
const signal = controller.signal;
// 超过 mininmalRtt 的请求,直接取消
setTimeout(() => {
controller.abort();
resolve(null);
}, mininmalRtt);
for(let ip of ips) {
const startTime = Date.now();
fetch(`http://${ip}/ping`, { signal }).finally(() => {
const rtt = Date.now() - startTime;
if (rtt < mininmalRtt) {
resolve({
ip,
rtt,
})
}
// 取消其他请求
controller.abort();
})
}
});
}