Promise是什么
1、Promise是js中的一个原生对象,是一种异步编程的解决方案。可以替换掉传统的回调函数解决方案,将异步操作以同步的流程表达出来。
2、Promise有三种状态:pending(初始化)、fulfilled(成功)、rejected(失败)
可以通过resolve()与reject()改变当前的promise对象的状态
● resolve()使当前promise对象状态改为fulfilled
● reject()使当前promise对象状态改为rejected
● 一般抛出异常也会导致promise对象状态改为rejected
3、相关概念
回调函数:当一个函数作为参数传入另一个函数中,当满足一定条件后该函数才执行,这种函数就称为回调函数。例如我们熟悉的定时器就存在回调函数。
同步任务:同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行下一个任务。
异步任务:异步任务不进入主线程,而是进入异步队列,前一个任务是否执行完毕不影响下一个任务的执行。
为什么使用Promise
Promise对象提供了简洁的API,使得控制异步操作更加容易。可以很好地解决回调地狱问题
1、回调地狱
为了在异步函数当中顺序执行代码而而不断嵌套调用回调函数,例如以下代码:
javascript
setTimeout(() => {
console.log('setTimeout1');
setTimeout(() => {
console.log('setTimeout2');
setTimeout(() => {
console.log('setTimeout3');
}, 1000);
}, 2000);
}, 3000);// 分别输出setTimeout1、setTimeout2、setTimeout3
2、Promise链式编程解决回调地狱
javascript
getPromise(str, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(str)
}, time);
});
}
const p1 = this.getPromise('setTimeout1', 3000);
const p2 = this.getPromise('setTimeout2', 2000);
const p3 = this.getPromise('setTimeout3', 1000);
p1.then((data1) => {
console.log(data1);
return p2;
})
.then((data2) => {
console.log(data2);
return p3;
})
.then((data3) => {
console.log(data3);
})// 依次输出setTimeout1、setTimeout2、setTimeout3
基本用法
1、 new实例化一个promise对象,构造函数中接收一个函数作为参数,该函数支持传入2个参数resolve和reject。
2、将需要处理的异步任务写在该函数内,异步任务执行成功时调用resolve返回结果,执行失败时调用reject回调函数。
3、通过promise.then接收处理成功时响应的数据,catch接收处理失败时响应的数据。
javascript
const promise1 = new Promise((resolve, reject) => {
axios.get("/api/mock-data/list/v1").then((e) => {
if (e.data.status == 200) {
resolve(e.data);
} else {
reject({errCode: -1});
}
});
});
promise1.then((data) => {
console.log('接口返回数据===',data);
})
.catch((err) => {
console.log('接口响应错误===',err);
});
// 模拟接口数据1:通过then()获取
{
status: 200,
message: 'success',
data: [{
id: 1,
name: 'xiaoming',
age: '21',
job: '前端工程师'
}, {
id: 2,
name: 'xiaozhang',
age: '28',
job: '后端工程师'
}]
}
// 模拟接口数据2:通过catch()捕获
{
status: 404,
message: 'Not Found',
data: null
}
常用API
promise.then():获取异步任务的成功结果,支持2个函数参数(成功和失败回调),一般来说then中只处理成功的
promise.catch():获取异步任务的失败结果,和then函数参数中失败回调作用一样,处理错误,由于Promise抛出错误具有冒泡性质,能够不断传递,会传到catch中,所以一般来说所有错误处理放在catch中,then中只处理成功的,同时catch还会捕捉resolved中抛出的异常(代码报错)
promise.finally():异步任务成功与否,都会执行
Promise.all():Promise.all([promise1,promise2])------参数是对象数组。以慢为准,等数组中所有的promise对象状态为resolved时,该对象就为resolved;只要数组中有任意一个promise对象状态为rejected,该对象就为rejected
javascript
const p1 = new Promise((resolve, reject) => {
resolve({ errCode: 0 });
});
const p2 = new Promise((resolve, reject) => {
resolve({ errCode: -1 });
});
const p3 = new Promise((resolve, reject) => {
resolve({ errCode: -2 });
});
const promises = Promise.all([p1, p2, p3]);
promises
.then((data) => {
console.log("Promise.all.then===", data);
})
.catch((err) => {
console.log("Promise.all.catch===", err);
});
// 运行结果为:Promise.all.then===
//[
// {
// "errCode": 0
// },
// {
// "errCode": -1
// },
// {
// "errCode": -2
// }
//]
const p1 = new Promise((resolve, reject) => {
resolve({ errCode: 0 });
});
const p2 = new Promise((resolve, reject) => {
reject({ errCode: -1 });
});
const p3 = new Promise((resolve, reject) => {
reject({ errCode: -2 });
});
const promises = Promise.all([p1, p2, p3]);
// const promises = Promise.race([p2, p1, p3]);
promises
.then((data) => {
console.log("Promise.all.then===", data);
})
.catch((err) => {
console.log("Promise.all.catch===", err);
});
// 运行结果为:Promise.all.catch===
//{
// "errCode": -1
//}
Promise.race():Promise.race([promise1,promise2])------参数是对象数组。以快为准,数组中所有的promise对象,有一个先执行了何种状态,该对象就为何种状态,并执行相应函数
javascript
const p1 = new Promise((resolve, reject) => {
reject({ errCode: 0 });
});
const p2 = new Promise((resolve, reject) => {
resolve({ errCode: -1 });
});
const p3 = new Promise((resolve, reject) => {
resolve({ errCode: -2 });
});
const promises = Promise.race([p2, p1, p3]);
promises
.then((data) => {
console.log("Promise.all.then===", data);
})
.catch((err) => {
console.log("Promise.all.catch===", err);
});
// 运行结果为:Promise.all.then===
//{
// "errCode": -1
//}
Promise缺点
代码冗余,异步任务通过new Promise包装后,都需要使用then调用,导致一眼看出都是then..then..then,不利于代码维护。
async/await
async/await 是ES7提出的基于Promise的解决异步的最终方案。
async:是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。因此对async函数可以直接then,返回值就是then方法传入的函数。
javascript
async fn() {
return 123456;
},
this.fn().then((data) => {
console.log('async===',data);
})
// 输出为:async=== 123456
// 注意:未加async修饰的函数,是不能直接.then的
await: 也是一个修饰符,只能放在async定义的函数内。可以理解为等待 。
await 修饰Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行;
示例:
javascript
async fn() {
let data = '';
axios.get("/api/mock-data/list/v1").then((e) => {
data = e.data;
});
console.log('data===',data);// 输出data值为''
}
await修饰后:new Promise可以省略
javascript
async fn() {
let data = '';
data = await new Promise((resolve, reject) => {
axios.get("/api/mock-data/list/v1").then((e) => {
resolve(e.data);
});
});
console.log('data===',data);// 输出data为接口返回值
}
总结:await实际会暂停函数的执行,直到promise状态变为完成,然后继续执行。
javascript
async fn() {
console.log('123');
let data1 = await new Promise((resolve, reject) => {
axios.get("/api/mock-data/list/v1").then((e) => {
resolve(e.data);
});
});
let data2 = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 3000);
});
console.log('456');
console.log('data1===',data1);
console.log('data2===',data2);
},
this.fn();//立即输出123,3秒后分别输出456、data1、data2
tips
当浏览器出现报错Uncaught (in promise) err时,检查是否有reject错误未捕获,增加catch分支即可。