提起promise,大家都不陌生,像我们平时常见的axios请求数据等都是基于promise进行封装的
简单认识:promise是异步编程的一种方案,解决了地狱回调的问题,是一种链式调用的方式;同时它是一个构造函数,对外提供统一的API,自身有all reject resolve等方法,原型上有then catch等方法
promise的有关内容
通过上图,我们认识到了promise的简单结构,以下内容是经过对promise的一些简单简单操作得到的结论
1.promise 是处理异步回调的解决方案;
2.promise 对象是一个容器,里面包裹了一个(些)异步操作,表示一个预计在未来完成的异步操作
3.promise 有一个参数是回调函数,这个回调函数有两个参数;resolve(成功后的回调函数) reject(失败后的回调函数)
4.promise 有三种状态[promiseState]:pending(进行中) fulfilled(已成功) rejected(已失败)
5.promise的状态只有两个可能: pending---fulfilled pending---rejected
6.promise的状态一旦发生改变就会凝固,会一直保持这个状态,不会再发生变化
7.promise状态一旦发生改变,就会触发promise的then的方法,then方法中有两个回调函数,一个是成功后的回调,一个是失败后的回调
8.promise一旦创建成功就立即执行(new Promise是同步,后面的.then是异步);reject() resolve()不会阻塞代码的执行
9.在创建promise时,如果代码报错,那么会自动走.then中的reject回调函数
.catch主要是为了捕获.then方法中的报错
手动写一个报错,可以用于终止代码运行
throw new Error()
//
1) .then中的reject用于捕获 创建的new Promise 中的报错
2) .catch用来捕获.then中的报错
3) 若.then中没有reject的回调,则需要.catch来捕获创建的new promise中的报错
10.promise中的finally方法,无论promise是成功或是失败也无论catch方法是否执行,最终finally方法都会执行
.finally((ll)=>{
console.log('fina',ll)
})
Promise的API
所谓的API(Application Program Interface),应用程序接口,和我们用的方法,并不是一回事,比如说数组,它里面的pop是它的方法,而isArray就是它的API,promise中的API如下
1.Promise.all()
-
里面的promise实例都是并行的,但是需要等到所有的promise执行完成之后才会有结果;
-
如果都执行成功,就正常返回,有一个失败,就失败
1.Promise.all()
- 里面的promise实例都是并行的,但是需要等到所有的promise执行完成之后才会有结果;
- 如果都执行成功,就正常返回,有一个失败,就失败
1.当p1 p2 p3都执行完成后,pAll的状态变成已成功,返回的结果是参数的顺序
2.如果有任意一个失败,那么pAll的状态都会变成失败,返回rejected
3.如果参数中的promise对象有任意一个promise没有正常返回的话,pAll的状态都会变成失败,并将失败的那个的结果返回出来
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p1')
},1000)
})
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p2')
},3000)
})
let p3=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p3')
},1000)
})
let pAll=Promise.all([p1,p2,p3])
pAll.then(res=>{}).catch(err=>{})
2.promise.race()
-
返回的也是一个对象,race谁先有结果,就返回谁无论成功还是失败(成功就走resolve,失败就会在reject中返回)
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('p1')
},1000)
})
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('p2')
},2000)
})
let pRace=Promise.race([p1,p2])
//先打印 p1
pAll.then(res=>{}).catch(err=>{})
3.Promise.reject()
4.Promise.resolve()
拓展:promise的简写方式
应用场景:需要使用promise上面的方法,但不需要请求数据,直接使用promise let p1 = Promise.resolve("let p1 = Promise.resolve"); //p1完全等价于p2 let p2 = new Promise((resolve, reject)=>{ resolve("let p1 = Promise.resolve"); })
promise解决回调地狱
举个小例子:我们在填写住址的时候,常请求省市县的信息,像这样下一个请求的内容依赖于上一次请求的内容的,也就是我们的三级联动问题
let p1=new Promise((resolve,reject)=>{
setTimeOut(()=>{
//请求省的逻辑
},100)}).then(res=>{
return new Promise((resolve,reject)=>{
setTimeOut(()=>{
//请求市的逻辑
},100)}).then(res=>{
return new Promise((resolve,reject)=>{
setTimeOut(()=>{
//请求县的逻辑
},100) })
注意:设置setTimeOut()是为了模拟环境,实现异步;真实开发中,该位置是 请求数据的逻辑
练练手吧
使用promise结合和promise的api实现图片的加载,要求所有的图片加载完毕后,才显示出来
let imgList = document.getElementById('imgListBox')
//
//封装promise,里面进行图片请求的逻辑
//
let loadImg = function(src) {
return new Promise((resolve, reject) => {
//
let img = document.createElement('img')
//给img标签添加属性 src
img.src = src
//图片加载成功时的函数
img.onload = () => {
resolve(img) //将创建好的ing标签返回出去
}
img.onerror = () => {
reject(new Error("图片加载失败"))
}
})
}
let p1 = loadImg('图片路径');
let p2 = loadImg('图片路径');
let p3 = loadImg('图片路径');
....
//
//
//因为 promise.all的参数 为迭代器 interable 所以传一个数组
let pAll = Promise.all([p1, p2, p3,...])
pAll.then(res => { //res是装有 img标签的盒子
res.forEach(item => {
imgList.appendChild(item)
})
})
思考:如果图片加载出错,页面还要给出提示,该怎木写?(偷偷给个提示,使用到promise.race)
一起写写吧!