一只sync和一只wait

最近有一个包里用了不少async await,但是细细看了一下发现很多地方用的比较奇怪,比如同步的函数,没有用到await也用async,就稍微整理了一下相关的使用,没有实现原理相关的内容,以示例为主,有点像面试题。参考了一些文章,就不单独罗列了,一搜还挺多的。

async返回了什么

async返回一个promise,这个大家应该都很清楚,那么看一下这个例子,看看是否能区分

async function sleep(second) {
  // 把这个return去掉和不去掉,输出有什么区别
  return await new Promise(resolve => {
    resolve("sleeped");
  });
}
console.log(sleep().then(console.log));

上面这个例子,sleep函数写了return的时候,返回的是await后面的promise,打印出的是sleeped,去掉return,打印出的是undefined,可以认为,这时候async返回的是一个隐藏的Promise.resolve(),我们可以用以下例子来验证

async function num(){
  return 33;
}
console.log(num());
console.log(Promise.resolve(33));

循环中的async

先来看看for中使用async的姿势

(async function() {
  for (let i = 0; i < 3; i++) {
    // 这个例子其实是考察Promise的
    await new Promise(res => {
      res();
      console.log(i);
    });
  }
  console.log(123);
})();

(async function() {
  for (let i = 0; i < 3; i++) {
    await new Promise(res => {
      res(i);
      // setTimeout(()=>res(i), 3000);
    }).then(console.log);
  }
  console.log(123);
})();

再来看看map中使用async的姿势,使用map有两个地方可以放await,一个是map前面,一个是map内的函数,

(async function() {
  await [1,2,3].map(i=>{
    // 如果这个例子的结果和你想的不一样,可以想想map返回了啥
    // 注意这个return
    return new Promise(res => {
      res(i);
      // 如果写成这样,结果会不会不一样
      // setTimeout(()=>res(i), 3000);
    }).then(console.log);
  })
  console.log(123);
})();

(async function() {
  [1,2,3].map(async i=>{
    // 这里最外层的那个async没啥用
    await new Promise(res => {
      res(i);
      // 如果写成这样,结果会不会不一样
      // setTimeout(()=>res(i), 3000);
    }).then(console.log);
  })
  console.log(123);
})();

第一个例子,map返回的其实是一个数组,里面有三个Promise,所以如果想要等待map中的Promise执行完毕,需要在map外面包一个Promise.all。
第二个例子,先输出了123,应该不是一般需要的那种结果。
如果仔细的话,会发现使用定时3秒输出的时候,map的两个例子是3个一起输出的,而for循环的3个输出是一个接一个。
其他的循环类型,可以自己试一试

到底要不要wait

async function sleep(second) {
  await new Promise(res=>{
    console.log(789)
    setTimeout(()=>res(123), 3000);
  }).then(console.log);
}
(async function(){
  // 这个await去掉和不去掉的区别
  await sleep();
  console.log(456);
})()

我开始看到这个例子的时候,觉得调用sleep的时候可以不需要await,因为sleep自己带有await,等待Promise执行完毕,但是一试,发现和我想的不一样,如果打印出sleep的返回,就比较清楚了,sleep()返回了一个Promise(这个我们在开头就说了),所以如果不带上await,后面的console是不会等待sleep的,所以如果需要同步调用一个async函数,一定要await,不管它里面写成啥样(如果它内部直接返回常数,可以试试上面那个返回33的例子)

并行的async

在一些情况下我们是需要并行多个Promise的,比如多个请求一起发送,那么就不能一个一个await下来,比较常用的Promise.all肯定没问题,上面提到的map也可以,还发现了一种,别人写的,但是忘了记录是哪篇文章,看一下例子

async function fetchUserParallel () {
  const namePromise = new Promise(res=>setTimeout(_=>res('name'),3000))
  const avatarPromise = new Promise(res=>setTimeout(_=>res('avatar'),3000))
  // 这种形式挺有意思的
  return {
    name: await namePromise,
    avatar: await avatarPromise 
  }
}
(async function () {
  console.time('should be 3s : ')
  const user2 = await fetchUserParallel()
  console.log(user2)
  console.timeEnd('should be 3s : ')
})()

错误处理

最简单和常用的就是try catch,catch有两种写法(可能更多)

try{
  await promise();
}catch(){
  ...
}

await promise().catch(){
  ...
};

还有一种,也是看来的,很有意思

function transform(promise) {
  return promise
    .then(data => {
      // 其实也可以只返回一个值,通过判断返回值的类型来区分是否出错了
      return [null, data];
    })
    .catch(err => [err]);
}
(async function asyncTask() {
  let err, data;
  [err, data] = await transform(promiseRequest);
  if (err) {
    // ...
  } else {
    // ...
  }
})()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值