await 与 promise.race 可自然配合实现“取最快结果”或“超时控制”,典型场景包括带超时的网络请求、多 cdn 资源竞速加载及用户操作中断自动流程,均通过 await 消费 race 返回的 promise 并用 try/catch 处理结果。

await 和 Promise.race 可以自然配合使用,核心在于:用 await 等待一个由 Promise.race 构造的竞速 Promise,从而在异步流程中实现“取最快结果”或“带超时控制”的逻辑。这种组合既保持了代码的同步可读性,又保留了 race 的响应优先特性。
处理带超时的网络请求
这是最典型也最实用的场景。直接 await 一个 fetch 调用可能无限等待;而用 Promise.race 包裹 fetch 和 timeout Promise,就能让 await 在超时前就退出。
- 创建一个超时 Promise,reject 带明确错误信息
- 用 Promise.race 同时竞争 fetch 请求和超时 Promise
- 用 await 消费 race 返回的 Promise,配合 try/catch 捕获成功或超时异常
示例代码:
async function fetchWithTimeout(url, ms) {const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), ms);
const fetchPromise = fetch(url, { signal: controller.signal });
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Request timed out after ${ms}ms`)), ms)
);
return await Promise.race([fetchPromise, timeoutPromise]);
}
try {
const res = await fetchWithTimeout('/api/data', 3000);
const data = await res.json();
console.log(data);
} catch (err) {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error(err.message); // 如 "Request timed out after 3000ms"
}
}
从多个镜像源加载资源(如图片、脚本)
当有多个 CDN 或备用地址提供同一资源时,可以并发发起请求,用 race 获取最先成功的那个,提升首屏加载速度。
- 对每个 URL 构建一个加载 Promise(例如 Image 加载、动态 import)
- 用 Promise.race 封装所有加载 Promise
- await race 结果,直接拿到最快加载完成的资源路径或模块
示例(加载图片):
async function loadFastestImage(urls) {const promises = urls.map(url =>
new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(url);
img.onerror = () => reject(new Error(`Failed to load ${url}`));
img.src = url;
})
);
return await Promise.race(promises);
}
// 使用
try {
const src = await loadFastestImage(['/cdn1/logo.png', '/cdn2/logo.png']);
document.getElementById('logo').src = src;
} catch (err) {
console.warn('All image sources failed:', err);
}
用户操作中断自动流程
比如页面 3 秒后自动跳转,但允许用户点击按钮提前跳转——这时可以把“自动跳转”和“用户点击”两个事件封装为 Promise,用 race 决出谁先触发。
- 用 Promise 封装 setTimeout(自动跳转)
- 用 Promise 封装一次性的事件监听(如 button.click)
- await Promise.race,哪个先 resolve 就执行对应动作
示例(自动跳转 vs 手动跳转):
async function waitForRedirectOrClick() {const autoRedirect = new Promise(resolve =>
setTimeout(() => {
console.log('Auto redirecting...');
resolve('auto');
}, 3000)
);
const userClick = new Promise(resolve => {
document.getElementById('skip-btn').addEventListener('click', () => {
console.log('User skipped');
resolve('user');
}, { once: true });
});
return await Promise.race([autoRedirect, userClick]);
}
// 使用
const winner = await waitForRedirectOrClick();
if (winner === 'user') {
location.href = '/dashboard';
} else {
location.href = '/welcome';
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











