setTimeout/Promise/AsyncAwait的区别
(1)setTimeout
setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行
(2)Promise
Promise本身是同步的立即执行函数,当在exector中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,等主栈完成后,才会去调用resolve/reject中存放的方法执行
|
|
|
|
(3)async/await
async函数返回一个Promise对象,当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了async函数体
|
|
异步编程的发展历程
一个任务分成两段,先执行一段,转而执行其他任务,等做好了准备转而执行第二段
回调函数->Promise->Generator->async await
(1)回调函数(callback)
函数B作为参数(函数引用)传递到另一个函数A中,并且这个函数A执行函数B。我们就说函数B叫做回调函数
✔️优点:解决了异步问题
❌缺点:回调地狱,多个回调函数嵌套的情况,使代码看起来十分混乱,不易于维护
|
|
(2)Promise
用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作
✔️优点:可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
❌缺点:
- 无法取消Promise
- 错误需要通过回调函数来捕获
- 当处于pending状态时,无法得知目前进展到哪一个阶段
|
|
API | 用法 |
---|---|
Promise.then | 实例化后的Promise对象可以进行链式调用 |
Promise.catch | 捕获异常操作时出现的异常 |
Promise.all() | 将数组中所有的任务执行完成之后,才能执行.then中的任务。全部为fulfilled时,它才会变成fulfilled,否则变成rejected |
Promise.race() | 一旦参数内有一个值的状态发生的改变,那么该Promise的状态就是改变的状态 |
Promise.resolve() | 接受一个参数值,可以是普通的值,具有then()方法的对象和Promist实例 |
Promise.reject() | 接受一个参数值reason,即发生异常的原因 |
(3)Generator
- 在function关键字后加一个*,那么这个函数就称之为generator函数
- 函数体有关键字yield,后面跟每一个任务,也可以有return关键字,保留一个数据
- 通过next函数调用,几个调用,就是几个人任务执行
yield后面的星号也跟生成器有关
✔️优点:没有了Promise的一堆then(),异步操作更像同步操作,代码更加清晰
❌缺点:不能自动执行异步操作,需要写多个next()方法,需要配合使用Thunk函数和co模块才能做到自动执行
|
|
(4)async await
(与generator有关),async await是语法糖,内部是generator+promise实现async函数就是将Generator函数的星号(*)替换成async,将yield替换成await
(与promise有关)
放在一个函数前的async有两个作用:
- 使函数总是返回一个promise
- 允许在这其中使用await
promise前面的await关键字能够使JavaScript等待,直到promise处理结束。然后:
- 如果它是一个错误,异常就产生了,就像在那个地方调用了throw error一样
- 否则,它会返回一个结果,我们可以将它分配给一个值
✔️优点:代码清晰,不用像Promise写一大堆then链,处理了回调地狱的问题。很显然,async/await比promise更容易理解
❌缺点:await将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用await会导致性能上的降低
|
|
(5)为什么Async/Await更好?
-
简洁:由示例而知,使用Async/Await明显节约了不少代码。我们不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。这些小的优点会迅速累计起来,这在之后的代码示例中会更加明显
-
错误处理:Async/Await让try/catch可以**同时处理同步和异步错误。**在下面的promise示例中,try/catch不能处理JSON.parse的错误,因为它在Promise中。我们需要使用.catch,这样错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂
-
可读性:使用async/await编写可以大大提高可读性
-
错误栈:Promise链中返回的错误栈没有给出错误发生位置的线索。更糟糕的是,它会误导我们:错误站中唯一的函数名为callAPromise,然而它和错误没有关系(文件名和行号还是有用的)
-
调试:最后一点,也是非常重要的一点在于,async/await能够使得代码调试更简单