Promise 、async、await 的学习
js的同步和异步
首先我们需要复习一下 js 的同步和异步
JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务,为了防止 ajax 这类任务执行等待时间过长,javascrpit 就设计了同步和异步任务
同步任务
同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务
异步任务
异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务
Es6的Promise异步规范
在 Es6 的 Promise 出来之前,我们一般都是使用回调函数来处理异步任务 ,在Promise规范提出后,异步编程就变的相对简单一些
Promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
Promise并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
Promise包括以下几个规范
- 一个promise可能有三种状态:等待
pending
、已完成fulfilled
、已拒绝rejected
- 一个promise的状态只可能从
等待
转到完成
态或者拒绝
态,不能逆向转换,同时完成
态和拒绝
态不能相互转换- promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致(即链式的then方法调用)
- then方法接受两个参数,(一般我们叫第一个回调参数为
res
、第二个为err
) ,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由等待
态转换到拒绝
态时调用,同时,then
可以接受另一个promise
传入,也接受一个“类then”的对象或方法,即thenable对象
我们可以通过 if(typeof(Promise)==="function")
来测试浏览器是否支持promise
通过 new Promise
来进行 Promise
对象的创建
1 | new Promise( |
Promise.then()
的链式调用示例,then
被按照顺序组织起来,一个一个的执行,每个执行完后就会变成 完成
状态并进行下一个
前面也提到了,then方法其实是接受两个参数,虽然大部分时候我们都比较关注成功时的回调,但第二个参数失败的回调可以帮我们处理一些异常,除此之外,我们还可以使用catch
来捕获错误,reject
的东西一定进入 then
的第二个回调,当没有写第二个回调的时候,会进入catch
,如果没有then
, 也可以直接进入catch
。
err处理异常
和catch
都会返回一个promise实例,并且是resolved状态所以不会影响后续的then
的执行,否则将会把后续的then
的状态变为rejected
并且不会执行他们所登记的异步函数
then的链式调用 | 出错的then的链式调用 | ||||
---|---|---|---|---|---|
|
|
async 和 await
async
是作为函数的修饰符放在函数的前面 , 它的调用会返回一个promise
对象,并且Promise
还有PromiseStatus
和promiseValue
,如果async
函数本身返回值,当调用该函数成功时内部会调用Promise.solve()
方法把它转化成一个promise
对象作为返回,如果 函数内部抛出错误,就会调用Promise.reject()
返回一个promise
对象,想要获取到async
函数的执行结果,就要调用promise的then
或catch
来给它注册回调函数总结一下,
async
函数的执行会返回一个promise
对象,并且把内部的值进行promise
的封装。如果promise
对象通过then
或catch
方法又注册了回调函数,async
函数执行完以后,注册的回调函数就会放到异步队列中,等待执行
await
关键字只能放到async
函数里面,await
是等待的意思,等待直到Promise
对象resolve
,得到resolve
的值作为await
表达式的运算结果,我们一般在需要拿到请求数据后再操作的情况下使用。
执行下面的代码我们可以看到每等2秒会输出一个值,6秒后 三个数的和 和 第三个数几乎一起输出
1 | // 2s 之后返回双倍的值 |