promise.any适合cdn备用加载,因其在任一promise成功时立即resolve且忽略其余失败,天然适配择优加载;需手动包装fetch加abortcontroller实现超时,注意跨域与兼容性降级。

Promise.any 为什么适合 CDN 备用加载
Promise.any 在至少一个 Promise 成功时就立即 resolve,其余失败会被静默忽略——这正契合“多个 CDN 同时请求,谁快用谁”的核心逻辑。它不等全部完成,也不因某条线路超时或 404 就整体失败,天然适配资源择优场景。
注意:它和 Promise.race 不同。Promise.race 遇到第一个 reject(比如网络超时)就会直接 reject,而 Promise.any 只有全部 reject 才 reject,更健壮。
常见错误现象:Uncaught (in promise) AggregateError —— 这不是 bug,是 Promise.any 全部失败后的正常抛错,必须显式捕获。
如何构造带超时控制的 CDN 加载 Promise
CDN 请求本身没有内置超时,需手动包装。直接用 fetch + AbortController 是最可控的方式:
- 每个 CDN URL 单独配一个
AbortController,避免互相干扰 - 超时时间建议设为 3–5s;太短易误判,太长拖慢首屏
- 务必在
fetch中传入signal,否则超时无效 - 对非 2xx 响应(如 404、503)主动 throw,让
Promise.any忽略该路
function loadFromCDN(url, timeout = 4000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
<p>return fetch(url, { signal: controller.signal })
.then(res => {
clearTimeout(id);
if (!res.ok) throw new Error(<code>HTTP ${res.status}</code>);
return res;
})
.catch(err => {
clearTimeout(id);
throw err;
});
}</p>
实际加载 script 或 CSS 时怎么接续
Promise.any 返回的是第一个成功的 Response 对象,不是脚本内容。要执行 JS 或注入 CSS,得自己处理后续:
- 加载 JS:用
response.text()获取字符串,再动态创建<script></script>标签或用eval(不推荐) - 加载 CSS:用
response.text()+ 动态插入<style></style>标签 - 注意跨域限制:CDN 必须开启
Access-Control-Allow-Origin: *,否则response.text()会失败 - 如果只关心加载成功与否(如字体、图片),可跳过
text(),直接 resolve
const urls = [
'https://cdn-a.example.com/lib.js',
'https://cdn-b.example.com/lib.js',
'https://cdn-c.example.com/lib.js'
];
<p>Promise.any(urls.map(u => loadFromCDN(u)))
.then(response => response.text())
.then(code => {
const script = document.createElement('script');
script.textContent = code;
document.head.appendChild(script);
})
.catch(err => {
console.error('所有 CDN 均不可用', err.errors);
});</p>
兼容性与降级方案必须考虑
Promise.any 在 Safari 15.4+、Chrome 93+、Firefox 97+ 支持。旧浏览器会报 Promise.any is not a function。
- 不能只靠
try/catch检测,得先判断是否存在:if ('any' in Promise) - 降级可用
Promise.race+ 手动计数,但逻辑复杂且容错差;更稳妥是 fallback 到主 CDN + 简单重试 - 构建时若目标环境明确(如只支持现代浏览器),可不加 polyfill;否则推荐用
core-js的Promise.any实现
真正容易被忽略的是:CDN 域名 DNS 解析耗时也影响“谁先回来”。如果所有 URL 都指向不同域名,首次加载可能因 DNS 查询阻塞而拉平响应差异。上线前建议用 performance.getEntriesByType('navigation') 查看各 CDN 的 domainLookupEnd - domainLookupStart 差异。











