参考文章:https://jakearchibald.com/2017/await-vs-return-vs-return-await/
引子
意外的看到了以下两种写法,到底他们有什么区别呢,接下来这篇文章就是对 await return 以及 return await
的超详细介绍了,千万不要错过哦!
const connection = await createConnection() return connection // and return await createConnection()
开始
当我们写异步函数的时候,很容易遇到await, return, return await的情形,写对正确的是非常重要的,下面我们根据实例来判断到底怎么选择。
首先定义一个异步函数 waitAndMaybeReject
,这个函数有一半的概率为成功 —— 返回 ‘yay’,有另一半的概率抛出一个错误 —— Error(‘Boo!’)
async function waitAndMaybeReject() { // 执行耗时一秒钟 await new Promise(r => setTimeout(r, 1000)); // 掷硬币 const isHeads = Boolean(Math.round(Math.random())); if (isHeads) return 'yay'; // 一半成功 throw Error('Boo!'); // 一半抛出错误 }
下面我们总览一下执行的结果:
接下来我们对一下几种情形进行分析:重点是异常情况哦!
知识点回顾
你需要知道的事情:
await foo()
async function foo() { await waitAndMaybeReject(); }
当await waitAndMaybeReject();
执行时:
- await 会暂停当前函数
foo
,等待 promise 处理完成; - 如果promise正常处理(fulfilled),其回调的 resolve 函数的参数将作为 await 表达式的值,接着继续执行
async function foo
; - 如果promise异常(rejected),await 会把异常原因抛出;
- 另外的,如果 await 操作符后的表达式不是promise,则返回值本身。
没有await
async function foo1() { try { waitAndMaybeReject(); } catch (e) { return 'caught'; } }
结果: 立马返回undefined。
分析: 执行 foo1
时,由于 waitAndMaybeReject
是异步函数,所以try...catch
只能捕获到同步的错误,所以最终啥也没闹到,最后返回 undefined。
await
async function foo2() { try { await waitAndMaybeReject(); } catch (e) { return 'caught'; } }
错误情形图解:
结果:
- 结果1秒钟后返回;
- waitAndMaybeReject 成功时,return undefined;
- waitAndMaybeReject 失败时,return ‘caught’。【异常被捕获】
分析:
- await 和 async 联合使用,是一个串行的异步函数;
- waitAndMaybeReject 成功时,只执行 try 块区域,由于没有返回值,所以默认返回 undefined;
- waitAndMaybeReject 失败时,会抛出错误,catch 块区域捕获到错误内容,返回 ‘caught’。
return
async function foo3() { try { return waitAndMaybeReject(); } catch (e) { return 'caught'; } console.log(4); // 不会被执行 }
由于这里直接将函数 waitAndMaybeReject
return 了出去,所以后面的内容都不会被执行!(例如上面的console.log(4))
错误情形图解:
结果:
- 结果1秒钟后返回;
- waitAndMaybeReject 成功时,return ‘yay’,函数
foo3
执行结束; - waitAndMaybeReject 失败时,抛出错误 Error(‘Boo!’),函数
foo3
执行被终止。【异常 未捕获】
分析:
- await 和 async 联合使用,是一个串行的异步函数;
- waitAndMaybeReject 成功时,只执行 try 块区域,return 获取到的是 ‘yay’,所以返回 ‘yay’;
- waitAndMaybeReject 失败时,
return 获取到抛出的错误,函数执行被终止,catch 块区域不会捕获到错误
。
return await
async function foo4() { try { return await waitAndMaybeReject(); } catch (e) { return 'caught'; } }
结果:
- 结果1秒钟后返回;
- waitAndMaybeReject 成功时,return ‘yay’;
- waitAndMaybeReject 失败时,return ‘caught’。
以上代码可以看做下面,一切就很好理解了:
async function foo4_() { try { const fulfilledValue = await waitAndMaybeReject(); return fulfilledValue; } catch (e) { return 'caught'; } }
分析:
- await 和 async 联合使用,是一个串行的异步函数;
- waitAndMaybeReject 成功时,只执行 try 块区域,fulfilledValue 的值是 ‘yay’,所以最终返回 ‘yay’;
- waitAndMaybeReject 失败时,try 块区域的 fulfilledValue 获取的是抛出的错误,catch 捕获错误,最终返回 ‘caught’。【异常被捕获】
特别提示:return await 只有在 try…catch 中可行,否则会报 eslint 冗余的错误。
详见:eslint
回应开头
所以开头提到的这两种写法,后者其实就是前者的简写!!!!哇!!!
const connection = await createConnection() return connection // and return await createConnection()
代码复制
以下代码为文章的测试代码,可直接拷贝后执行:
async function waitAndMaybeReject() { // Wait one second await new Promise(r => setTimeout(r, 1000)); // Toss a coin const isHeads = Boolean(Math.round(Math.random())); if (isHeads) return 'yay'; throw Error('Boo!'); } async function foo1() { try { waitAndMaybeReject(); } catch (e) { return 'caught'; } } async function foo2() { try { await waitAndMaybeReject(); } catch (e) { return 'caught'; } } async function foo3() { try { return waitAndMaybeReject(); } catch (e) { return 'caught'; } } async function foo4() { try { return await waitAndMaybeReject(); } catch (e) { return 'caught'; } } var test = async() => { console.log('pare') console.log(await foo1()) console.log('await') console.log(await foo2()) console.log('return') console.log(await foo3()) console.log('return await') console.log(await foo4()) } test()