51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

前端面试题:理解JavaScript中的Async/Await和Promise以及它们之间的区别

当你去面试前端开发的时候,经常会被问到异步的问题,比如JavaScript中的Async/Await和Promise,并且还需要让你大概说说它们之间的区别。今天我们就来详细的了解下。

Async/await

是一个用同步思维解决异步问题的方案

1、会自动将常规函数转换成Promise,返回值也是一个Promise对象
2、只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数
3、异步函数内部可以使用await
4、await 放置在Promise调用之前,await 强制后面点代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果
5、await只能在async函数内部使用,用在普通函数里就会报错

和Promise相比较

相同点:

为了解决异步流程问题,promise是约定,而async更优雅。

区别:

1、Promise是ES6,而async是ES7
2、Promise原来有规范的意义,Promise a,b,c,d 等规范,最终确定的是Promise a+ 规范
3、Promise链式操作,自己catch异常。async则要在函数内catch,好在现在catch成本较低
4、Promise有很多并行神器,比如Promise.all\Promise.race等。这些是async没法搞定的
5、Promise是显式的异步,而 Async/await 让你的代码看起来是同步的,你依然需要注意异步
6、Promise即使不支持es6,你依然可以用promise的库或polyfil,而async就很难做,当然也不是不能,成本会高很多
7、async functions 和Array.forEach等结合,很多tc39提案都在路上或者已经实现,处于上升期,而promise也就那样了

有同学问了,你讲这多,听不懂啊,不要着急,接下来,我们弄点实例来实际操作下吧。

实例

假设函数getJSON()返回一个Promise,基于Promise的调用示例如下:


const makeRequest = () =>
  getJSON()
    .then(data => {
      console.log(data)
      return "done"
    })
makeRequest()

getJSON()返回Promise后,在then()函数里输出结果,并返回done。 使用Async/Await改写如下:


const makeRequest = async () => {
  console.log(await getJSON())
  return "done"
}
makeRequest()

在函数前使用关键词async来标记这是一个异步函数,它隐含着表示函数会返回一个Promise,当函数返回值时就表示Promise被处理(resolve)了。

await关键字只能用在async标记的函数内,换句话说它是不能用在代码的最顶层。await的意思是等待getJSON()返回的Promise被处理了才会执行。

与Promise对比简洁干净与Promise需要使用then()函数来处理Promise返回的结果,而async/await则直接在代码按顺序上处理结果,代码量减少的同时,显得更简洁。

错误处理

async/await让我们可以同时捕获异步和同步代码抛出的异常。Promise如果在then()函数里出现异常,在Promise的外面的try/catch是捕获不到,这种情况我们需要使用Promise的catch()函数。如:


const makeRequest = () => {
  try {
    getJSON()
      .then(result => {
        // this parse may fail
        const data = JSON.parse(result)
        console.log(data)
      })
      .catch((err) => {
        console.log(err)
      })
  } catch (err) {
    console.log(err)
  }
}

async/await异步代码和同步代码共用try/catch。


const makeRequest = async () => {
  try {
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}

条件语句

有一种情况是我们会对返回的Promise数据做判断,如果符合某种条件则需要发起另外一个异步请求。使用Promise示例如下:

const makeRequest = () => {
  return getJSON()
    .then(data => {
      if (data.needsAnotherRequest) {
        return makeAnotherRequest(data)
          .then(moreData => {
            console.log(moreData)
            return moreData
          })
      } else {
        console.log(data)
        return data
      }
    })
}

这种嵌套的Promise读起来很容易迷糊。 async/await改写如下:

const makeRequest = async () => {
  const data = await getJSON()
  if (data.needsAnotherRequest) {
    const moreData = await makeAnotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}

看起来像同步代码,大大增强了异步代码的可读性。

中间值

有一种情况是需要通过多个嵌套的请求,其中前面的请求返回的是一个中间值,后面的请求需要使用中间值来发起请求。使用Promise如下:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      // do something
      return promise2(value1)
        .then(value2 => {
          // do something          
          return promise3(value1, value2)
        })
    })
}

async/await改写就很简单:


const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

另外,Async/Await也很方便我们调试代码。

总结

Async/awati 简单好用,是大势,肯定得学,而async的使用绕不开Promise,所以Promise是必会的。

赞(0)
未经允许不得转载:工具盒子 » 前端面试题:理解JavaScript中的Async/Await和Promise以及它们之间的区别