记录一下异步的事儿

404 阅读3分钟

之前对于异步也就停留在 async/await 的使用及简单的一些理解上,最近工作碰到一些问题,解决之后来做个记录。

在此之前首先要知道什么是异步,异步都有哪些,假如 await console.log('异步?') 显然此刻的await是形同虚设和console.log('异步?')效果是一样的。也就是说async/await只有用在异步操作上才生效,否则形同虚设。

假如现在有个场景,我们需要同时调用三个api(api请求当然就是异步操作了),我们想要在api请求成功之前给页面加一个loading,但是我们要求第一个api返回之后取消loading,再进行下面两个api的请求,这时候我们可以用Promise.race或者Promise.all也可以用async/await ,但是需要注意的是他们的区别,也就是我们要怎么用。

首先看看 Promise.racePromise.all的区别:

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值,且其中一个失败就代表失败。

let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
  resolve('success')
})

let p3 = Promse.reject('失败')

Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失败了,打出 '失败'
})

Promse.racerace顾名思义就是赛跑的意思,意思就是说,Promise.race([p1, p2])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  },1000)
})

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('failed')
  }, 500)
})

Promise.race([p1, p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)  // 打印的是 'failed',因为reject只需要0.5秒
})

对应到我们的需求我们可以

const p1 = '第一个api请求' // 这里用文字代表api请求了
Promise.race([p1]).then((result) => { //结合上面的解释,这里我们用Promise.all是一样的效果
  // 这里请求成功,返回值,但是我们不需要在这里有什么操作
}).catch((error) => {
  // 这里请求失败,返回值,我们做了统一的错误处理,所以也不需要做什么操作
})
this.loading = false // 我们在此处把loading关掉即可,总不能一直让也面处于loading状态
// 然后我们在进行下面的两个api请求即可
const p2 = '第二个api请求'
const p3 = '第三个api请求'

说完了Promise.racePromise.all,我们来看看 async/await是如何解决问题的。

假如我们

async doSomething () { // await肯定要用在 async函数里面
    await this.getFirstApi() //此处getFirstApi代表第一个api请求
    this.loading = false
    this.getSecondApi() //此处模拟第二个api请求
    this.getThirdApi() //此处模拟第三个api请求
}

像上面这种写法肯定是不行的,因为假设第一个请求'挂掉'了,那么我们下面两个api请求将被'卡死'在这个地方,永远不会继续下去,所以我们需要借用try/catch来解决一下

async doSomething () { // await肯定要用在 async函数里面
    try {
        await this.getFirstApi() //此处getFirstApi代表第一个api请求
    } catch {
      //这里请求失败,做了失败处理
    }
    this.loading = false
    this.getSecondApi() //此处模拟第二个api请求
    this.getThirdApi() //此处模拟第三个api请求
}

这样的话我们就可以保证首先请求第一个api,且第一个api处理过后取消页面loading状态,又不会卡住剩下的两个api的请求了。