今天手机上的Boss直聘突然弹出个消息: “promise和async-await有什么区别?”。
打开手机后,看了各路大神各抒己见,于是自己也找了找资料,以下是自己的总结和各路大神的回答。
1. 关于async-await的
以下均摘自MDN
async函数是使用
async
关键字声明的函数。 async函数是AsyncFunction
构造函数的实例, 并且其中允许使用await
关键字。async
和await
关键字让我们可以用一种更简洁的方式写出基于Promise
的异步行为,而无需刻意地链式调用promise
。
async函数可能包含0个或者多个
await
表达式。await表达式会暂停整个async函数的执行进程并出让其控制权,只有当其等待的基于promise的异步操作被兑现或被拒绝之后才会恢复进程。promise的解决值会被当作该await表达式的返回值。使用async
/await
关键字就可以在异步代码中使用普通的try
/catch
代码块。
await
关键字只在async函数内有效。如果你在async函数体之外使用它,就会抛出语法错误SyntaxError
。
async
/await
的目的为了简化使用基于promise的API时所需的语法。async
/await
的行为就好像搭配使用了生成器和promise。
async函数一定会返回一个promise对象。如果一个async函数的返回值看起来不是promise,那么它将会被隐式地包装在一个promise中。
2. 关于Promise的
promise
的精髓是状态的传递,方法的封装者并不需要关心异步方法的执行结果,方法的封装者通过状态传递拿到执行结果书写自己的逻辑,使得封装者与使用者的真正解耦。这种状态传递有种发布订阅的味道,回调地狱并非书写上的地狱而诟病,promise 的链式调用也会有地狱之感,而回调地狱真正为之诟病的是没有真正解耦。async 是 promise 的语法糖。
在 Promise 为出现之前,我们用回调函数来编写异步程序,来满足日常开发的异步需求。随着前端的发展,代码的日益增多,逻辑逐渐复杂,大量使用回调函数的代码,让程序员开始头疼。代码可读性低、维护困难、大量前台回调函数,看的程序员是直接怀疑人生。
为了解决工程师们面临的这个问题,Promise 诞生了。它提供了一些 API,让工程师们可以用一种新的方式来编写异步程序。通过 then 方法来写异步程序执行成功后执行的代码,用 catch 方法来捕捉异常,而且可以链式调用。 函数地狱和回调函数造成的程序可读性差的问题,被解决了,小伙伴们又可以快乐的编程了。
等等,似乎还有个问题没有被解决。在使用 Promise 的时候,可能会一个 Promise 中有多个 Promise。如果是多个独立的 Promise,可以用 Promise. all 来解决,但是它们之间如果彼此之间有依赖关系,需要有特定的执行顺序,这个时候 Promise 就无法解决了。 Promise 也遇到问题了,怎么办,该怎么解决呢?
就在工程师们发愁的时候,Async/Await“脚踏七彩祥云”出现在了工程师面前,说到:“你的问题我来解决”。 Async/Await 允许异步程序用同步的方式执行,这样两个异步且有依赖关系的程序不仅可以按照先后顺序执行,而且对于其它同步程序来说,它仍然是异步的,不会阻塞主线程。 就这样 Promise 产生的问题,被 Async/Await 解决了,工程师们终于可以放心大胆的去写程序了。
最后说一下,Async/Await 是在 Promise 的基础上实现的,它的返回值仍然是一个 Promise,所以工程师们仍然可以链式的使用 then 或 catch 等 API。
3. 相同点
Promise
和async-await
都是优化异步编程体验的解决方案。
4.不同点
Promise
是应用层的解决方案,它有一个规范,不同的语言也可以实现,它只能异步的处理错误,在js
里它本质上是一个对象。async-await
是语言层的解决方案,它可以说是Promise
的补充,可以让用户像编写同步代码一样编写异步代码,通过try-catch
可以同步地处理错误。Promise
更多应用在函数封装中,async
用在函数的使用中。Promise
链式调用相当于一个新的回调地狱, 也不能统一处理异常。Promise
本身是同步函数,多个不会等待。async-await
用同步的写法使得可读性更强,同时方便try-catch
捕获异常,async-await
有明确的前后关系,可读性好。