您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# JavaScript中Promise.allSettled()怎么用
## 引言
在现代JavaScript开发中,异步编程是不可或缺的一部分。随着ES6引入Promise对象,处理异步操作变得更加优雅和高效。而在ES2020(ES11)中新增的`Promise.allSettled()`方法,则为Promise的组合处理提供了更灵活的方式。本文将深入探讨`Promise.allSettled()`的使用方法、适用场景以及与类似方法的对比。
## 一、Promise.allSettled()基础
### 1.1 方法定义
`Promise.allSettled()`是一个静态方法,接收一个Promise可迭代对象(通常是数组)作为参数,返回一个新的Promise。这个新Promise会在所有输入的Promise都"settled"(即已兑现或已拒绝)后兑现,并返回一个包含每个Promise结果的对象数组。
```javascript
const promises = [promise1, promise2, promise3];
Promise.allSettled(promises)
.then(results => {
// 处理结果
});
每个结果对象都有以下结构:
当Promise兑现时:
{ status: 'fulfilled', value: <兑现值> }
当Promise拒绝时:
{ status: 'rejected', reason: <拒绝原因> }
特性 | Promise.allSettled() | Promise.all() |
---|---|---|
对拒绝的处理 | 不短路,等待所有Promise完成 | 短路,任一拒绝立即拒绝 |
返回值 | 始终兑现,带状态描述数组 | 全部兑现才兑现,否则拒绝 |
适用场景 | 需要知道所有Promise最终状态 | 需要所有Promise都成功 |
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>
setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises)
.then((results) =>
results.forEach((result) => console.log(result)));
// 输出:
// {status: "fulfilled", value: 3}
// {status: "rejected", reason: "foo"}
const apiCalls = [
fetch('/api/user'),
fetch('/api/products'),
fetch('/nonexistent')
];
Promise.allSettled(apiCalls)
.then(results => {
const successful = results.filter(r => r.status === 'fulfilled');
const failed = results.filter(r => r.status === 'rejected');
console.log(`${successful.length} calls succeeded`);
console.log(`${failed.length} calls failed`);
successful.forEach(res => {
console.log('Data:', res.value);
});
failed.forEach(err => {
console.error('Reason:', err.reason);
});
});
在需要向多个API端点发送请求并希望收集所有响应(无论成功与否)时特别有用:
async function fetchMultipleEndpoints(endpoints) {
const promises = endpoints.map(endpoint =>
fetch(endpoint)
.then(response => response.json())
.catch(error => ({ error: true, message: error.message }))
);
return Promise.allSettled(promises);
}
// 使用示例
const endpoints = [
'https://api.example.com/users',
'https://api.example.com/products',
'https://api.example.com/invalid'
];
fetchMultipleEndpoints(endpoints)
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Endpoint ${index} success:`, result.value);
} else {
console.error(`Endpoint ${index} failed:`, result.reason);
}
});
});
实现表单多字段独立验证,收集所有验证错误:
function validateField(field, value) {
return new Promise((resolve, reject) => {
// 模拟异步验证
setTimeout(() => {
if (field === 'username' && value.length < 5) {
reject(`${field} must be at least 5 characters`);
} else if (field === 'email' && !value.includes('@')) {
reject(`${field} must be a valid email`);
} else {
resolve(`${field} is valid`);
}
}, Math.random() * 1000);
});
}
async function validateForm(formData) {
const validations = Object.entries(formData).map(
([field, value]) => validateField(field, value)
);
const results = await Promise.allSettled(validations);
const errors = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
if (errors.length > 0) {
throw new Error(`Validation failed: ${errors.join(', ')}`);
}
return 'Form is valid';
}
// 使用示例
const form = {
username: 'john',
email: 'john@example',
password: 'secret'
};
validateForm(form)
.then(console.log)
.catch(console.error);
async function runParallelTasks(tasks) {
const start = Date.now();
const results = await Promise.allSettled(tasks.map(task => task()));
console.log(`All tasks completed in ${Date.now() - start}ms`);
return {
succeeded: results
.filter(r => r.status === 'fulfilled')
.map(r => r.value),
failed: results
.filter(r => r.status === 'rejected')
.map(r => r.reason)
};
}
// 示例任务
const tasks = [
() => new Promise(resolve => setTimeout(() => resolve('Task 1 done'), 1000)),
() => new Promise((_, reject) => setTimeout(() => reject('Task 2 failed'), 800)),
() => new Promise(resolve => setTimeout(() => resolve('Task 3 done'), 1200))
];
runParallelTasks(tasks)
.then(({ succeeded, failed }) => {
console.log('Succeeded:', succeeded);
console.log('Failed:', failed);
});
async function processMultipleRequests(urls) {
try {
const results = await Promise.allSettled(
urls.map(url => fetch(url).then(res => res.json()))
);
const data = results
.filter(result => result.status === 'fulfilled')
.map(result => result.value);
const errors = results
.filter(result => result.status === 'rejected')
.map(result => result.reason);
return { data, errors };
} catch (error) {
// 这里不会捕获allSettled的异常,因为它总是resolve
console.error('Unexpected error:', error);
throw error;
}
}
function withTimeout(promise, timeout) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${timeout}ms`)), timeout)
)
]);
}
async function fetchWithTimeouts(urls, timeout) {
const requests = urls.map(url =>
withTimeout(fetch(url), timeout)
.then(response => response.json())
.catch(error => ({ error: error.message }))
);
const results = await Promise.allSettled(requests);
return results.map(result =>
result.status === 'fulfilled' ? result.value : { error: result.reason }
);
}
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
return await response.json();
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
async function fetchMultipleWithRetry(urls) {
const results = await Promise.allSettled(
urls.map(url => fetchWithRetry(url))
);
return {
successful: results
.filter(r => r.status === 'fulfilled')
.map(r => r.value),
failed: results
.filter(r => r.status === 'rejected')
.map(r => ({ url: r.reason.config.url, error: r.reason.message }))
};
}
Promise.allSettled()
在以下环境中原生支持:
- Node.js 12.9.0+
- Chrome 76+
- Firefox 71+
- Safari 13+
- Edge 79+
if (!Promise.allSettled) {
Promise.allSettled = function(promises) {
return Promise.all(promises.map(p =>
Promise.resolve(p).then(
value => ({ status: 'fulfilled', value }),
reason => ({ status: 'rejected', reason })
)
));
};
}
npm install core-js
// 在应用入口处
import 'core-js/features/promise/all-settled';
allSettled()
会保留所有Promise的结果,对于大量Promise需注意内存消耗Promise.allSettled(jobs)
.then(results => {
// 处理结果
})
.finally(() => {
// 清理资源
cleanup();
});
// 使用Promise.all() - 快速失败
Promise.all([successfulCall(), failingCall()])
.then(console.log)
.catch(error => {
console.error('One failed, all fail:', error);
});
// 使用Promise.allSettled() - 等待全部完成
Promise.allSettled([successfulCall(), failingCall()])
.then(results => {
const errors = results.filter(r => r.status === 'rejected');
if (errors.length > 0) {
console.warn(`${errors.length} calls failed`);
}
// 继续处理成功的结果
});
方法 | 描述 | 结果状态 |
---|---|---|
Promise.allSettled | 等待所有完成,返回所有状态 | 永不拒绝 |
Promise.race | 第一个settled的Promise | 可能兑现或拒绝 |
Promise.any | 第一个兑现的Promise | 全部拒绝时才拒绝 |
Promise.allSettled()
为JavaScript异步编程提供了重要的补充,特别适合以下场景:
- 需要知道多个异步操作的全部最终结果
- 部分失败不应阻止其他操作的执行
- 需要收集错误信息进行统一处理
通过本文的示例和解释,您应该已经掌握了如何在实际项目中有效使用这一强大的API。合理运用Promise.allSettled()
可以使您的异步代码更加健壮和可维护。
”`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。