1.promise是什么
(1)抽象表达: Promise是一门新的技术(es6规范);是JS种进行异步编程的新解决方案(旧方案是单纯使用回调函数) (2)具体表达:从语法上来说,Promise是一个构造函数;从功能上来说,Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
promise本身只是一个容器,真正异步的是它的两个回调resolve()和reject() **promise本质 不是控制 异步代码的执行顺序(无法控制) , 而是控制异步代码结果处理的顺序
异步操作包括:
- 回调函数 把一个函数当作参数传递,传递的是函数的定义并不会立即执行,而是在将来特定的时机再去调用,这个函数就叫做回调函数。
- 事件处理
- Ajax请求
- 定时器
2.为什么要用Promise
支持链式调用,可以解决回调地狱问题
什么是回到地狱?---回调函数的层层嵌套
回调地狱的缺点:
- 不便于阅读
- 不便于异常处理
- 代码可复用性不强
- 可维护性(迭代性差),扩展性差
3.Promise的初体验
如使用promise封装一个定时器
<body>
<h1>promise</h1>
<button id="btn">点我抽奖</button>
</body>
<script>
// 定义一个随机数
function rand (m,n){
return Math.ceil(Math.random() * (n-m+1) + m-1)
}
let btn = document.querySelector("#btn")
// 绑定点击事件
btn.addEventListener('click',function(){
// 使用promise封装
const p = new Promise((resolve,reject)=>{
// 定时器
setTimeout(()=>{
// 中奖概率1-100
// 获取从1-100的一个随机数
let n = rand(1,100)
// // 判断
if(n<=30) resolve(n)
reject(n)
})
})
//调用promise的then方法
p.then((res)=>{
alert('恭喜你中奖啦,奖品为10万元的购房优惠券,中奖号码为'+res)
},(err)=>{
alert('很遗憾,再试一次,本次抽奖号码为'+err)
})
})
</script>
4.Promise的状态
实例对象中的一个属性[PromiseState]
Promise的三种状态:
- pending 未决定的/进行中
- resolved/fullfilled 成功
- rejected 失败
Promise状态的改变:
- pending 变为 resolved
- pending 变为 rejected
[说明:只有这两种,且一个Promisez对象只能改变一次,无论变为成功还是失败都会有一个结果数据]
5.Promise 对象的值
实例对象中的另一个属性[PromiseResult]
保存着异步任务[成功/失败]的结果
- resolve
- reject
6.Promise的基本流程
7.Promise的api
Promise.prototype.then(onResolved,onRejected)=>{}
注意:new Promise在实例化的过程中所执行的代码都是同步进行的,而then中注册的回调才是异步执行的。
then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。then方法返回的是一个新的Promise实例,因此可以采用链式写法,即then方法后面再调用另一个then方法
Promise.prototype.catch(onRejected)=>{}
catch用于指定发生错误时的回调函数.,即如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。
1. // 写法一
1. const promise = new Promise(function(resolve, reject) {
1. try {
1. throw new Error('test');
1. } catch(e) {
1. reject(e);
1. }
1. });
1. promise.catch(function(error) {
1. console.log(error);
1. });
1.
1. // 写法二
1. const promise = new Promise(function(resolve, reject) {
1. reject(new Error('test'));
1. });
1. promise.catch(function(error) {
1. console.log(error);
1. });
Promise.prototype.finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作(ES2018 引入)
Promise.resolve():返回一个成功的promise对象
如果传入的参数为非Promise对象,则返回的结果为成功promise对象;如果传入的参数为promise对象,则参数的结果决定了resolve的结果
Promise.reject():返回一个失败的promise对象
Promise.all(): 完成并发任务,参数为包含n个promise的数组
返回一个新的promise实例,只有所有的promise都成功才成功,只要有一个失败了就直接失败
Promise.race(): 参数为包含n个promise的数组
返回一个新的promise,
第一个完成的promise的结果状态就是最终的结果状态
8.promise的几个关键问题
1.如何改变promise的状态
-
resolve:将promise状态由pending变为成功
-
reject:将promise状态由pending变为失败
-
抛出异常:throw,如果当前是 pending 就会变为 rejected
2.一个promise指定多个成功或失败回调函数,都会调用吗
- 会,当promise改变为对应状态时都会调用
3.改变promise状态和指定回调函数谁先谁后
- 都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调
- 如何先改状态再指定回调?
(1)在执行器中做同步任务,直接调用reslove()/reject()
(2)延迟调用then()
- 什么时候才能得到数据?
(1)如果先指定回调,当状态发生改变时,回调函数就会调用,得到数据
(2)如果先改变状态,那当指定回调时,回调函数就会调用,得到数据
4.promise.then()返回的新promise的结果状态由什么决定
由then()指定的回调函数执行的结果状态决定
5.promise如何串连多个操作任务
(1)promise的then方法返回一个新的promise,可以写成then()的链式调用
(2)通过then的链式调用可以串联多个同步或异步任务
6.promise的异常穿透
(1)当使用promise的then链式调用时,可以在最后使用catch指定失败的回调
(2)前面任何操作出了异常都会传到最后失败的回调中处理
7.中断promise链 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
方式:在回调函数中返回一个pending状态的promise对象
Promise.all、Promise.race、Promise.any的区别
all: 成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
race: 哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
any: 返回最快的成功结果,如果全部失败就返回失败结果。
8.Promise的问题:逍
Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担,并且Promise传递中间值⾮常麻烦
Promise的调试很差,由于没有代码块,你不能在⼀个返回表达式的箭头函数中设置断点,如果你在⼀个.then代码块中使⽤调试器的步进(step-over)功能,调试器并不会进⼊后续的.then代码块,因为调试器只能跟踪同步代码的每⼀步。
所以ES2017推出了新的语法async/await 来更好的解决异步问题。
9.async和await
一句话概括:它就是 Generator 函数的语法糖,也就是处理异步操作的另一种高级写法
(1)async + 函数
async关键字: 修饰函数。 表示这个函数内部有异步操作。
- 函数的返回值为promise对象
- promise对象的结果由async函数执行的返回值决定
-
- 如果返回值是一个非promise对象的数据,结果为成功的状态
-
- 如果返回的是一个promise对象,由promise对象的返回结果决定
-
- 抛出异常,throw,返回一个失败的结果和状态,通过try/catch处理失败的结果
(2)await + 表达式
await关键字: 等待异步执行完毕。
await只能用于被async修饰的函数中。 只有当await后面的异步操作执行完毕后,才会继续执行后面代码
1.await右侧的表达式一般为promise对象,但也可以是其他值
2.如果表达式是promise对象,await返回的是promise成功的值
3.如果表达式是其他的值,直接将此值作为await的返回值
async/await语法如下:
- 函数前面使用
async修饰 - 函数内部,promise操作使用
await修饰
- await 后面是promise对象, 左侧的返回值就是这个promise对象的then方法中的结果
- await必须要写在async修饰的函数中,不能单独使用,否则程序会报错
- 如果await的promise失败了,就会抛出异常,需要通过.catch()或者try/catch捕获处理
async语法的异常捕获
async函数内部的异常可以通过 .catch()或者 try/catch来捕获,区别是
-
try/catch 能捕获所有异常,try语句抛出错误后会执行catch语句,try语句内后面的内容不会执行
-
catch()只能捕获异步方法中reject错误,并且catch语句之后的语句会继续执行