一、为什么使用Promise?
我们知道 js 执行的时候,一次只能执行一个任务,它会阻塞其他任务。由于这个缺陷导致 js 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以使用回调函数执行。
常见的异步模式有以下几种:
- 定时器
- 接口调用
- 事件函数
上述定时器是在固定时间触发某个回调函数。
对于 ajax 网络请求就没有这么简单了,可能有多个网络请求是关联的,先执行某个请求返回结果后,第一个返回结果作为第二个请求的参数,调用第二个网络请求。如此,如果业务复杂,网络请求太多时,回调也很多,容易出现回调地狱。所以 Promise 出现了,专门解决异步回调地狱问题。
二、Promise基本使用
下列用到的所有定时器模拟我们的 ajax 请求。
Promise 实例化的时候,传入的参数是一个函数,函数中接收两个参数:resolve, reject
传入的 resolve 和 reject 本身都是函数。其作用分别为:
resolve - 把 Promise 的状态从进行中变为成功状态。
reject - 把 Promise 的状态从进行中变为拒绝状态。
Promise的三种状态:
pending :进行中,表示 Promise 还在执行阶段,没有执行完成。
fulfilled:成功状态,表示 Promise 成功执行完成。
rejected:拒绝状态,表示 Promise 执行被拒绝,也就是失败。
Promise 的状态,只可能是其中一种状态,从进行中变为成功或失败状态之后,状态就固定了,不会再发生改变。
Promise.then
执行 resolve 时,Promise 状态变为 fulfilled ,会执行 .then 方法。then 方法接收的参数也是一个函数,函数中携带一个参数,该参数是 resolve(res) 返回的数据。
Promise.catch
执行 reject 时,Promise 状态从 pending 变为 rejected,会执行 catch 方法,catch 方法接收的也是一个函数,函数中携带一个参数,该参数为 reject(err) 返回的数据。
三、用asyn/await来处理异步
async的用法,它作为一个关键字放到函数前面,只有一个作用, 它的调用会返回一个promise 对象。async 函数也是函数,所以它的调用和普通函数的调用没有什么区别,直接加括号调用就可以了。
<script>
var p1 = new Promise((resolve, rej) => {
// console.log('没有 resolve')
//throw new Error('手动返回错误')
rej('失败了')
})
p1.catch(
res => {
console.log('catch data1:', res)
})
async function p2(res, rej) {
throw new Error('错了')
}
p2().catch(
rej => {
console.log('catch data2:', rej)
})
async function p3(res, rej) {
return '成功了'
}
p3().then(
res => {
console.log(res)
}
)
</script>
控制台输出结果:
对比async 关键字创建的函数和普通的期约对象。
接下来关注await关键字。
如果promise对象通过then或catch方法又注册了回调函数,async函数执行完以后,注册的回调函数就会放到异步队列中,等待执行。如果只是async, 和promise 差不多,但有了await就不一样了, await 关键字只能放到async 函数里面,await是等待的意思,那么它等待什么呢,它后面跟着什么呢?其实它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果。
现在写一个函数,让它返回promise 对象,该函数的作用是2s 之后让数值乘以2
在没有使用await关键字等待时,控制台输出结果如下
在使用了await之后
控制台1.5秒后输出220
这里强调一下等待,当js引擎在等待promise resolve 的时候,它并没有真正的暂停工作,它可以处理其它的一些事情,如果我们在testResult函数的调用后面,console.log 一下,你发现后面console.log的代码先执行。
控制台输出:
四、宏任务与微任务
微任务: Promise, async/await
宏任务: setTimeOut, setTimeInterval, DOM事件, Ajax
在执行栈执行完毕之后 EventLoop事件循环之前,这二者之间有一个浏览器尝试渲染DOM的过程
微任务的执行是在渲染DOM之前,宏任务的执行是在渲染DOM之后。
注意DOM渲染和DOM结构改变是不一样的,异步的是DOM的渲染,DOM结构的改变是同步的???
从EventLoop解释 为什么微任务执行更早?
微任务是ES语法规定的,宏任务是浏览器规定的。
场景题 async/await 语法
**第一题 **
a等于一个Promise
b等于100
第二题
打印start
- await后面跟一个数字相当于直接返回这个数字,因此a是100
- await后面跟一个promise.resolve() await相当于.then 因此b是200
- await之后跟一个Promise.reject() 会报错 代码中断在这里。
then和catch的返回
如果then和catch代码中没有抛出错误也没有返回值 那么返回的就是一个resolve的Promise
如果抛出错误 那么返回的就是一个reject的Promise