Promise
1.认识Promise
Promise是异步操作的一种解决方法
回调函数
document.addEventListener('click', () => {
console.log("这里是异步的!");
});
console.log("这里是同步的!");
2.什么时候使用Promise
Promise一般用来解决层层嵌套的回调函数(回调地狱callback hell)的问题
3.Promise的基本用法
3.1 实例化构造函数生成实例化对象
Promise解决的不是回调函数,而是回调地狱
const p = new Promise(()=>{});
3.2 Promise的状态
Promise的状态一旦变化,就不会再改变了
Promise有三种状态,一开始是pending(未完成),执行resolve,变成fulfilled(resolved),已成功,执行reject,变成rejected,以失败
const p = new Promise((resolve, reject) => {
//pending->fulfilled
// resolve();
//pending->rejected
//reject();
});
console.log(p);
3.3 then方法
3.3.1什么时候执行
pending-->fulfilled时,执行then的第一个回调函数
pending-->rejected时,执行then的第二个回调函数
3.3.2 执行后的返回值
then方法执行后返回一个新的Promise对象
3.3.3 then方法返回的Promise对象的状态改变
const p = new Promise((resolve,reject)=>{
reject();
});
p.then(()=>{
console.log('success');
},()=>{
console.log('err'); //err
//在then的回调函数中,return后面的东西,会用Promise包装一下
return 123;
//等价于
// return new Promise((resolve,reject)=>{
// //默认情况下就调用resolve,默认返回的永远是成功状态的Promise对象
// resolve(123);
// })
//如果想要返回失败的的状态,就手动写完整
//return new Promise((resolve,reject)=>{
// reject(123);
})
}).then((data)=>{
console.log('success2',data); // success2 123
},(err)=>{
console.log('err2',err); //err2 123
})
const p = new Promise((resolve, reject) => {
resolve();
// reject();
});
p.then(()=>{
console.log('success'); //success
},()=>{
console.log('error');
})
3.4resolve和reject函数的参数
// 执行成功
const p = new Promise((resolve, reject) => {
//resole('succ');
resolve({username:'LiHao'});
// reject();
});
p.then((data)=>{
console.log('success',data); //success {username: "LiHao"}
},()=>{
console.log('error');
});
//执行失败
const p = new Promise((resolve, reject) => {
// resolve({username:'LiHao'});
reject(new Error('reason'));
});
p.then((data)=>{
console.log('success',data);
},(err)=>{
console.log('error',err); // error Error: reason
})
4.catch()
4.1catch()有什么用
catch专门用来处理rejected状态
catch本质上是then的特例
4.2基本用法
//catch()可以捕获它前面的错误
//一般总是建议,Promise对象后面要跟catch()方法,这样可以处理Promise内部发生的错误
new Promise((resolve, reject) => {
// resolve(123);
reject('reason')
}).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
})
5.finally()方法
5.1什么时候执行
当Promise状态发生变化时,不论如何变化都会执行,不变化不执行
new Promise((resolve,reject)=>{
// resolve(123)
reject('reason');
}).finally(data=>{
console.log(data); //undfined
}).catch(err=>{})
5.2本质
finally()本质上是then()的特例
6.Promise.resolve()和Promise.reject()
6.1 Promise.resolve()是成功状态Promise的一种简写形式
new Promise(resolve=>resolve('foo'));//简写Promise.resolve('foo');//参数//一般参数Promise.resolve('foo').then(data=>{ console.log(data);//foo })
const p1 = new Promise(resolve=>{ setTimeout(resolve,1000,'我执行了'); //等价于 // setTimeout(()=>{ // resolve('我执行了'); // },1000); }) Promise.resolve(p1).then(data=>{ console.log(data);//一秒之后执行,打印'我执行了' }) //等价于 p1.then(data=>{ console.log(data); }); console.log(Promise.resolve(p1)===p1)//true
当resolve函数接收的是Promise对象时,后面的then会根据传递的Promise对象的状态变化决定执行哪一个回调
//概括就是 这个then是否执行是由p1的状态来决定的new Promise(resolve => resolve(p1).then(data=>{ console.log(data); //我执行了}))
具有then方法的对象
const thenable = { then(resolve, reject) { console.log('then'); //then resolve('data'); // reject('reason'); } }; Promise.resolve(thenable).then(data => console.log(data), err => console.log(err) //data )
6.2Promise.reject()是失败状态Promise的一种简写形式
new Promise(reject=>reject('reason'));//简写Promise.reject('freason');//参数//不管什么参数,都会原封不动地向后传递,作为后续方法的参数
7.Promise.all()
7.1有什么用
Promise.all()关注多个Promise对象的状态变化
传入多个Promise实例,包装成一个新的Promise实例返回
7.2基本用法
Promise.all()的状态变化为所有传入的Promise实例对象状态有关
所有状态都变成resolved,最终的状态才会变成resolved
只要有一个变成rejected,最终的状态就变成rejected
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }) } const p1 = delay(1000).then(() => { console.log('p1完成了'); return 'p1'; }); const p2 = delay(2000).then(() => { console.log('p2完成了'); return 'p2'; }); const p = Promise.all([p1, p2]); p.then(data => { console.log(data); }, err => { console.log(err); })
8.Promise.race()和Promise.allSettled()
8.1Promise.race()
Promise.race()的状态取决于第一个完成的Promise实例对象,如果第一个完成的成功了,那最终就是成功,如果第一个完成的失败了,那最终的就失败
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }) } const p1 = delay(1000).then(() => { console.log('p1完成了'); return 'p1'; }); const p2 = delay(2000).then(() => { console.log('p2完成了'); return 'p2'; }); const racePromise = Promise.race([p1, p2]); racePromise.then(data => { console.log(data); // p1 只跟第一个有关 }, err => { console.log(err); })
8.2Promise.allSettled()
Promise.allSettled()的状态与传入的Promise状态无关,永远都是成功的,它只会忠实的记录下各个Promise的表现
const delay = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }) } const p1 = delay(1000).then(() => { console.log('p1完成了'); // return 'p1'; return Promise.reject('err'); }); const p2 = delay(2000).then(() => { console.log('p2完成了'); return 'p2'; }); const allSettledPromise = Promise.allSettled([p1, p2]); allSettledPromise.then(data => { console.log(data); }, err => { console.log(err); })
9.Promise的注意事项
9.1resolve或reject函数执行后的代码
推荐在调用resolve或reject函数的时候加上return,不再执行他们后面的代码
9.2Promise.all/race/allSettled的参数问题
参数如果不是Promise数组,会将不是Promise的数组元素转变成Promise对象
Promise.all([1,2,3]).then(data=>{ console.log(data); //[1,2,3] }); //等价于 Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3) ]).then(data=>{ console.log(data); //[1, 2, 3] })//不只是数组,任何可遍历的都可以作为参数//数组、字符串、Set、Map、arguments、NodeList
10.Promise的应用
异步加载图片
<img id='img' src="https://images.pexels.com/photos/7647498/pexels-photo-7647498.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt=""> <script> const loadImgAsync = url => { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { resolve(img); }; img.onerror = ()=>{ reject(new Error(`Could not load image at ${url}`)); }; img.src = url; }); }; const imgDOM = document.getElementById('img'); loadImgAsync('https://images.pexels.com/photos/8066135/pexels-photo-8066135.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500').then(img=>{ console.log(img.src); imgDOM.addEventListener('click',()=>{ imgDOM.src = img.src; },false) }).catch(err=>{ console.log(err); }) </script>