Promise.reject
和 throw new Error
在异步函数中的差异:
🔍 主要差异
1. 语法和行为差异
typescript
// 方式1: Promise.reject
async function upload1() {
if (!files) {
return Promise.reject('没有选择文件'); // 返回一个被拒绝的Promise
}
}
// 方式2: throw new Error
async function upload2() {
if (!files) {
throw new Error('没有选择文件'); // 抛出异常,自动包装成被拒绝的Promise
}
}
2. 实际执行结果
typescript
// 测试代码
async function test() {
try {
await upload1(); // 会进入catch块
} catch (error) {
console.log('upload1 error:', error); // '没有选择文件'
}
try {
await upload2(); // 也会进入catch块
} catch (error) {
console.log('upload2 error:', error); // Error: 没有选择文件
}
}
�� 详细对比
特性 | Promise.reject |
throw new Error |
---|---|---|
语法 | 显式返回Promise | 抛出异常 |
错误类型 | 直接返回错误值 | 抛出Error对象 |
堆栈跟踪 | 可能丢失堆栈信息 | 保留完整堆栈信息 |
调试体验 | 较差 | 更好 |
代码一致性 | 混合使用 | 统一异常处理 |
TypeScript支持 | 需要额外类型处理 | 更好的类型推断 |
�� 为什么推荐 throw new Error
?
1. 更好的调试体验
typescript
// Promise.reject 方式
async function badExample() {
if (error) {
return Promise.reject('Something went wrong');
}
}
// throw new Error 方式
async function goodExample() {
if (error) {
throw new Error('Something went wrong');
}
}
// 调用时
try {
await badExample(); // 错误信息: 'Something went wrong'
await goodExample(); // 错误信息: Error: Something went wrong at goodExample
} catch (error) {
console.log(error.stack); // throw方式有完整的堆栈信息
}
2. 代码一致性
typescript
// 混合使用 - 不推荐
async function inconsistent() {
if (condition1) {
return Promise.reject('error1');
}
if (condition2) {
throw new Error('error2'); // 混用
}
if (condition3) {
return Promise.reject('error3');
}
}
// 统一使用 throw - 推荐
async function consistent() {
if (condition1) {
throw new Error('error1');
}
if (condition2) {
throw new Error('error2');
}
if (condition3) {
throw new Error('error3');
}
}
3. TypeScript 类型安全
typescript
// Promise.reject 可能导致类型问题
async function typeIssue() {
if (error) {
return Promise.reject('string error'); // 返回 Promise<never>
}
return 'success'; // 返回 Promise<string>
// 函数返回类型变成 Promise<string | never>
}
// throw new Error 类型更清晰
async function typeSafe() {
if (error) {
throw new Error('string error'); // 抛出异常,不影响返回类型
}
return 'success'; // 返回 Promise<string>
// 函数返回类型保持 Promise<string>
}
🔧 实际应用场景
在异步函数中的最佳实践:
typescript
async function uploadImages(files: File[]) {
// 参数验证
if (!files || files.length === 0) {
throw new Error('没有选择文件'); // ✅ 推荐
// return Promise.reject('没有选择文件'); // ❌ 不推荐
}
// 业务逻辑错误
if (!isValidFormat(files)) {
throw new Error('不支持的文件格式'); // ✅ 推荐
}
try {
// 网络请求等可能失败的操作
const result = await fetch('/api/upload', { body: files });
if (!result.ok) {
throw new Error(`上传失败: ${result.statusText}`); // ✅ 推荐
}
return result.json();
} catch (error) {
// 重新抛出或处理错误
throw new Error(`上传过程中发生错误: ${error.message}`);
}
}
📝 总结
在 async/await
函数中,throw new Error
比 Promise.reject
更推荐,因为:
- 语法更简洁 - 直接抛出异常,无需显式返回Promise
- 调试更友好 - 保留完整的错误堆栈信息
- 代码更一致 - 统一使用异常处理机制
- 类型更安全 - TypeScript 类型推断更准确
- 符合现代JavaScript最佳实践 - 大多数现代框架和库都推荐这种方式
这就是为什么我在代码检查中建议将 Promise.reject
改为 throw new Error
的原因!