一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第八天,点击查看活动详情。
最近使用promise比较多,这里总结一下它的用法
祝愿看到文章的朋友身体健康;如果可以麻烦一键三连
Promise
Promise诞生的原因
- Promise诞生之前,我们处理异步请求时,通常在回调函数中处理
- 若需要执行多个异步请求,每一个请求又依赖上一个请求的结果
- “回调地狱”
- 可读性差
- 耦合度高,难以维护和复用
- 回调函数都是匿名函数,不方便调试
// 第一个请求
$.ajax({
url:'url1',
success:function(){
// 第二个请求
$.ajax({
url:'url2',
success:function(){
// 第三个请求
}
})
}
})
Promise的生命周期
- pending(进行中)、fulfilled(已成功)和rejected(已失败)
- Promise在创建时处于pending状态,状态的改变只有两种可能
- 一种是在Promise执行成功时,由pending状态改变为fulfilled状态
- 一种是在Promise执行失败时,由pending状态改变为rejected状态
- Promise状态只改变一次
Promise的基本用法
- Promise本身是一个构造函数
- Promise执行的过程是:
- 在接收的函数中处理异步请求,然后判断异步请求的结果
- 若结果为“true”,则表示异步请求执行成功,调用resolve()函数,resolve()函数一旦执行,Promise的状态就从pending变为fulfilled
- 若结果为“false”,则表示异步请求执行失败,调用reject()函数,reject()函数一旦执行,Promise的状态就从pending变为rejected
- resolve()函数和reject()函数可以传递参数,作为后续.then()函数或者.catch()函数执行时的数据源
Promise在创建后会立即调用,然后等待执行resolve()函数或者reject()函数来确定Promise的最终状态
let promise = new Promise(function(resolve,reject){
console.log('promise1');
resolve();
console.log('promise2');
})
promise.then(function(){
console.log('resolve');
})
console.log('hello');
//首先是Promise的创建,会立即执行,输出“promise1”,“promise2”
//然后是执行resolve()函数,这样的话就会触发then()函数指定回调函数的执行,但是它需要等当前线程中的所有同步代码执行完毕,因此会先执行最后一行同步代码,输出“hello”
//最后是当所有同步代码执行完毕后,执行then()函数,输出“resolve”
// 输出顺序为:promise1、promise2、hello、resolve
所以有了promise之后,ajax请求可以实现为
let ajaxRequest1 = new Promise(function(resolve,reject){
$.ajax({
url:'url',
success:function(){
resolve();
}
})
})
ajaxRequest1.then(function(){
console.log('resolve');
})
Promise中的函数
then()
- Promise在原型属性上添加了一个then()函数,在Promise实例状态改变时执行的回调函数
- 接收两个函数作为参数
- 第一个参数为Promise执行成功后调用resolve()函数时函数传递的参数
- 第二个参数是可选的,表示的是Promise在执行失败后(即调用了reject()函数或抛出了异常),执行的回调函数
- then()函数返回的是一个新的Promise实列
- 可以使用链式调用
- 上一轮then()函数内部return的值会作为下一轮then()函数接收的参数值
- then()函数中不能返回Promise实例本身,否则会出现Promise循环引用的问题,抛出异常
const promise = new Promise((resolve,reject) =>{
resolve(1);
reject(2);
});
promise.then((result)=>{
console.log(result);//1
return 3
},(result)=>{
// 不会输出,因为执行resolve()函数改变了Promise的状态,Promise的状态一旦改变,就会永久保持该状态,不会再次改变
console.log(result);
}).then((result)=>{
console.log(result);//3
});
const promise = new Promise((resolve,reject) =>{
reject(2);
resolve(1);
});
promise.then((result)=>{
// 不会输出,因为执行reject()函数改变了Promise的状态,Promise的状态一旦改变,就会永久保持该状态,不会再次改变
console.log(result);
return 3
},(result)=>{
console.log(result);// 2
}).then((result)=>{
console.log(result);//undefined
})
catch()
- 虽然then()函数里面也能处理rejected状态的Promise的回调函数,但是不推荐
- catch()函数是Promise执行失败之后的回调,接收的参数是reject()函数传递的参数
- 在Promise执行过程中出现了异常,会自动触发reject(err),不需要手动调用
const promise = new Promise((resolve,reject) =>{
null.name;
});
promise.catch((err)=>{
console.log(err);
//TypeError: Cannot read properties of null (reading 'name')
})
Promise.all()
- then()函数和catch()函数是Promise原型链中的函数,因此每个Promise的实例可以进行共享
- all()函数是Promise本身的静态函数,用于将多个Promise实例包装成一个新的Promise实例
const promise1 = new Promise((resolve,reject) =>{
null.name;
});
const promise2 = new Promise((resolve,reject) =>{
resolve(1);
});
const promise3 = new Promise((resolve,reject) =>{
resolve(2);
});
const allPromise = Promise.all([promise1,promise2,promise3]);
allPromise.then((res)=>{
console.log(res);
}).catch((res)=>{
console.log(res);
//TypeError: Cannot read properties of null (reading 'name')
})
const promise1 = new Promise((resolve,reject) =>{
resolve(1);
});
const promise2 = new Promise((resolve,reject) =>{
resolve(1);
});
const promise3 = new Promise((resolve,reject) =>{
resolve(2);
});
const allPromise = Promise.all([promise1,promise2,promise3]);
allPromise.then((res)=>{
console.log(res);//[1,1,2]
}).catch((res)=>{
console.log(res);
})
- 只有promise1、2、3全部的状态都变为fulfilled成功状态,allPromise的状态才会变为fulfilled状态
- promise1、2、3的返回值组成一个数组,作为allPromise的then()函数的回调函数的参数
- 只要promise1、2、3中有任意一个状态变为rejected失败状态,allPromise的状态就变为rejected状态
- 第一个被reject的实例的返回值会作为allPromise的catch()函数的回调函数的参数
- 如果在实例promise1、2、3中定义了catch函数,当其中一个Promise状态变为rejected时,不会触发Promise.all()函数的catch()函数
const promise1 = new Promise((resolve,reject) =>{
null.name;
}).catch(err => err);
const promise2 = new Promise((resolve,reject) =>{
resolve(1);
});
const promise3 = new Promise((resolve,reject) =>{
resolve(2);
});
const allPromise = Promise.all([promise1,promise2,promise3]);
allPromise.then((res)=>{
console.log(res);
//[TypeError: Cannot read properties of null (reading 'name'), 1, 2]
}).catch((res)=>{
console.log(res);
})
Promise.race()
- Promise.race()函数作用于多个Promise实例上,返回一个新的Promise实例
- 表示的是如果多个Promise实例中有任何一个实例的状态发生改变,那么这个新实例的状态就随之改变
- 最先改变的那个Promise实例的返回值将作为新实例的回调函数的参数
Promise.resolve()
- Promise提供了一个静态函数resolve(),用于将传入的变量转换为Promise对象
- 等价于在Promise函数体内调用resolve()函数
- Promise.resolve()函数执行后,Promise的状态会立即变为fulfilled,然后进入then()函数中做处理
Promise.reject()
- 等价于在Promise函数体内调用reject()函数
Promise用法
- Promise里面的代码和同步代码一起执行
let promise = new Promise(function(resolve,reject){
console.log('1');
resolve();
console.log('2');
})
promise.then(function(){
console.log('3');
})
console.log('4');
// 1 2 4 3
- 同一个Promise函数内只能执行一次resolve()函数或者reject()函数
let promise = new Promise(function(resolve,reject){
console.log('1');
reject();
resolve();
})
promise.then(function(){
console.log('2');
})
console.log('3');
// 1 3
// 2不会打印,因为执行reject()函数后Promise状态已经改变不能再次改变
- 同一个Promise实例自身重复执行
- 在then()函数中只要不是抛出错误的都会继续执行then()函数
let promise = new Promise(function(resolve,reject){
console.log('1');
resolve();
})
promise.then(function(){
console.log('2');
return new Error('error')
}).then((res)=>{
console.log('3');
console.log(`then:${res}`)
}).catch((res)=>{
console.log('4');
console.log(`catch:${res}`)
})
// 1
// 2
// 3
// then:Error: error
let promise = new Promise(function(resolve,reject){
console.log('1');
resolve();
})
promise.then(function(){
console.log('2');
return null.name
}).then((res)=>{
console.log('3');
console.log(`then:${res}`)
}).catch((res)=>{
console.log('4');
console.log(`catch:${res}`)
})
// 1
// 2
// 4
// catch:TypeError: Cannot read properties of null (reading 'name')
- then()函数接收的参数如果不是函数,会产生值穿透现象
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log);
// 1
//第一个then()函数接收一个值“2”,第二个then()函数接收一个Promise,都不是函数形式,因此这两个then()函数会发生值穿透现象
// 第三个then()函数因为接收到console.log()函数,因此会执行,此时接收的是最开始的resolve(1)的值,最终会输出“1”