async 函数中使用 await VS return VS return await 的异同

时间:2021-1-8 作者:admin

参考文章: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(); 执行时:

  1. await 会暂停当前函数 foo,等待 promise 处理完成;
  2. 如果promise正常处理(fulfilled),其回调的 resolve 函数的参数将作为 await 表达式的值,接着继续执行 async function foo
  3. 如果promise异常(rejected),await 会把异常原因抛出;
  4. 另外的,如果 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. 结果1秒钟后返回;
  2. waitAndMaybeReject 成功时,return undefined;
  3. waitAndMaybeReject 失败时,return ‘caught’。【异常被捕获】

分析:

  1. await 和 async 联合使用,是一个串行的异步函数;
  2. waitAndMaybeReject 成功时,只执行 try 块区域,由于没有返回值,所以默认返回 undefined;
  3. waitAndMaybeReject 失败时,会抛出错误,catch 块区域捕获到错误内容,返回 ‘caught’。

return

async function foo3() {
  try {
    return waitAndMaybeReject();
  }
  catch (e) {
    return 'caught';
  }
  console.log(4); // 不会被执行
}

由于这里直接将函数 waitAndMaybeReject return 了出去,所以后面的内容都不会被执行!(例如上面的console.log(4))

错误情形图解:

结果:

  1. 结果1秒钟后返回;
  2. waitAndMaybeReject 成功时,return ‘yay’,函数 foo3 执行结束;
  3. waitAndMaybeReject 失败时,抛出错误 Error(‘Boo!’),函数 foo3 执行被终止。【异常 未捕获】

分析:

  1. await 和 async 联合使用,是一个串行的异步函数;
  2. waitAndMaybeReject 成功时,只执行 try 块区域,return 获取到的是 ‘yay’,所以返回 ‘yay’;
  3. waitAndMaybeReject 失败时,return 获取到抛出的错误,函数执行被终止,catch 块区域不会捕获到错误

return await

async function foo4() {
  try {
    return await waitAndMaybeReject();
  }
  catch (e) {
    return 'caught';
  }
}

结果:

  1. 结果1秒钟后返回;
  2. waitAndMaybeReject 成功时,return ‘yay’;
  3. waitAndMaybeReject 失败时,return ‘caught’。

以上代码可以看做下面,一切就很好理解了:

async function foo4_() {
  try {
    const fulfilledValue = await waitAndMaybeReject();
    return fulfilledValue;
  }
  catch (e) {
    return 'caught';
  }
}

分析:

  1. await 和 async 联合使用,是一个串行的异步函数;
  2. waitAndMaybeReject 成功时,只执行 try 块区域,fulfilledValue 的值是 ‘yay’,所以最终返回 ‘yay’;
  3. 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()
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。