非立即使用async/await时try/catch块的正确放置方式
嘿,很高兴看到你已经把async/await用得这么顺手,还开始琢磨更高效的异步执行方式了!我来给你掰扯掰扯不同场景下try/catch该怎么放~
单个预启动的Promise场景
比如你先创建Promise,做一堆同步操作再await的情况:
let p = doSomethingAsync(); // 这里跑你的同步代码,比如处理数据、更新UI啥的 // ... await p;
这里分两种情况处理:
- 如果
doSomethingAsync()调用本身不会同步报错(比如不会因为参数错误直接throw,只会异步reject):那只需要把await p放进try/catch就行,因为异步错误只会在await的时候才会抛出:
let p = doSomethingAsync(); // 同步操作 try { await p; } catch (e) { console.error('异步操作出错啦:', e); }
- 如果
doSomethingAsync()可能有同步错误(比如参数校验不通过直接同步throw):那得把创建Promise的代码也塞进try块里,不然同步错误会直接跳出当前函数,根本到不了await那一步:
try { let p = doSomethingAsync(); // 这里如果同步报错,会被catch捕获 // 同步操作 await p; // 异步错误也会被catch捕获 } catch (e) { console.error('同步/异步错误:', e); }
并行执行多个Promise的场景
就是你同时启动p1和p2,先做同步操作再await的情况。这里要注意一个坑:如果直接分别await,前一个Promise的错误会被catch捕获,但后一个Promise如果reject了,可能会变成未处理的Promise错误(因为没人再去await它了)。
举个反例:
let p1 = doJob1(); let p2 = doJob2(); // 同步操作 try { await p1; await p2; } catch (e) { // 如果p1先reject,这里会捕获,但p2还在跑,它的reject会变成未处理错误 }
所以更稳妥的做法是用Promise.all把它们包起来,统一await,这样不管哪个先出错,都会被一起捕获,也不会有遗漏:
let p1 = doJob1(); let p2 = doJob2(); // 同步操作 try { await Promise.all([p1, p2]); // 两个任务都成功了才会到这里 } catch (e) { // 只要有一个任务reject,就会触发这里,e是第一个reject的错误 }
如果你确实需要分别处理两个任务的结果(比如不管p1成不成都要处理p2),那可以给每个await单独加try/catch:
let p1 = doJob1(); let p2 = doJob2(); // 同步操作 try { const result1 = await p1; // 处理p1的结果 } catch (e) { console.error('p1出错:', e); } try { const result2 = await p2; // 处理p2的结果 } catch (e) { console.error('p2出错:', e); }
这样不管p1是否成功,p2的错误都会被捕获,不会出现未处理的Promise问题。
核心原则总结
- Promise的错误会被“缓存”起来,只有当你用
await或者.catch()去处理它时,才会被抛出/捕获 - 只要在
await那个Promise的环节把它放进try/catch,就能捕获它的异步错误 - 如果创建Promise的过程(调用异步函数)可能产生同步错误,一定要把创建代码也放进try块
- 并行任务优先用
Promise.all统一处理错误,避免遗漏未处理的Promise reject
内容的提问来源于stack exchange,提问作者Jamona Mican
相关产品推荐
相关产品推荐

