Promise基础
1. Promise功能
-
回调函数嵌套回调函数被称作回调地狱,代码层层嵌套,环环相扣,很明显,逻辑稍微复杂一些,这样的程序就会变得难以维护。代码臃肿,可读性差,耦合度过高。
-
对于这种情况,程序员们想了很多解决方案(比如将代码模块化),但流程控制上,还是大量嵌套。
-
ES2015的标准里,Promise的标准化,一定程度上解决了JavaScript的流程操作问题。Promise对象是一个异步编程的解决方案,可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称'回调地狱')
//回调地狱案例
setTimeout(() => {
console.log("a数据请求回来了~");
setTimeout(() => {
console.log("b数据请求回来了~");
setTimeout(() => {
console.log("c数据请求回来了~");
}, 3000);
}, 2000);
}, 1000);
2. Promise入门
Promise是一个构造函数,自己身上有all、allSettled、any、race、reject、resolve这几个静态方法,原型上有then、catch、finally等方法Promise的构造函数接收一个参数,是回调函数,并且回调函数接受两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。new Promise()函数是同步执行的,只是用来处理异步的- Promise的实例化对象有两个属性
- PromiseState属性:当前Promise实例化对象的状态
- PromiseResult属性:当前Promise实例化对象的值
//promise的基本使用
const p1 = new Promise((resolve, reject) => {
//Promise内部是同步的,Promise只是用来处理异步的
console.log("promise内部");
//Promise是用来处理异步的,所以把异步代码写在Promise中
setTimeout(() => {
console.log("我是计时器");
//当异步完成以后,只需要调用resolve函数或者reject函数,就可以改变实例化promise对象的状态
resolve();
reject();
}, 2000)
})
console.log("p1", p1);
3. Promise实例的三种状态
-
pending 初始化状态(默认,异步代码还在执行中)
const promise = new Promise((resolve, reject) => { // 同步调用 //....code // 执行异步操作/异步代码 setTimeout(() => { console.log("setTimeout()"); }, 1000); }); console.log(promise) -
resolved / fulfilled 成功状态(异步代码执行成功了),调用resolve函数,可以将promise实例的状态由pending变成resolved,成功的promise实例的值为resolve的参数
const promise = new Promise((resolve, reject) => { setTimeout(() => { console.log("setTimeout()"); resolve('a数据'); }, 1000); }); console.log(promise) -
rejected 失败状态(异步代码执行失败了),调用reject函数,可以将promise实例的状态由pending变成rejected,失败的promise实例的值为resolve的参数
const promise = new Promise((resolve, reject) => { // 执行异步操作/异步代码 setTimeout(() => { console.log("setTimeout()"); reject("失败了~"); }, 1000); }); console.log(promise)
4. Promise的then方法
-
Promise.prototype.then可以接受两个回调函数作为参数, 捕获promise成功或失败的状态,执行成功或者失败的回调。 -
成功和失败的回调函数接受一个参数,是promise实例的值
-
then方法的回调函数是异步的,当调用then的实例化的promise实例不再是pending状态的时候,会执行then中的对应的成功或者失败的回调函数
-
因为then是解决异步嵌套的核心流程,所以then方法一定返回的是promise对象
-
then的返回值:
-
成功的promise实例调用then方法
- 默认:then返回的是一个成功的promise实例,promise实例的值就是当前回调函数的返回值
- 当then中返回的是一个promise实例的时候,then返回的promise实例的状态和值就是回调函数返回的promise实例的状态和值
- 当then的回调函数内部出现报错并且没有异常处理,则直接then返回失败的promise实例,值为这个错误
- then中只传递一个值,会直接发生值穿透,then返回成功状态的promise实例,值是调用then的promise实例的值
-
失败的promise对象调用then方法
- 当then中没有书写关于失败的回调函数的时候,会发生值穿透,直接返回失败的,值为调用catch的失败的promise实例的值
- 当then中书写了处理失败的回调函数,则返回值规则和成功状态then一样
- 成功的promise对象调用catch方法
- catch直接返回一个成功的promise对象,并且值是调用catch的那个成功的promise对象的值
const promise = new Promise((resolve, reject) => { setTimeout(() => { console.log("setTimeout()"); // console.log(333); resolve('a数据'); // reject("失败了~"); }, 1000); }); promise.then( (result) => { // 成功的回调 // 当promise对象的状态变成resolved,就会执行当前函数 // console.log("resolved 111"); console.log(result); return "then"; },(error) => { // 失败的回调 // 当promise对象的状态变成rejected,就会执行当前函数 // console.log("rejected 111"); console.log(error); } ) -
5. Promise的catch方法
-
Promise.prototype.catch可以接受一个回调函数作为参数, 捕获promise失败的状态,执行的回调。 -
规则和then方法中的 第二个回调函数一致
-
成功的promise对象调用catch方法,catch直接返回一个成功的promise实例,并且值是调用catch的那个成功的promise实例的值
6. Promise的finally方法
- 无论promise实例成功和失败都会进入finally中执行,当你书写的promise对象无论成功还是失败,都想要执行一段代码的时候,finally就是最佳解决方案
- finally的回调函数不接受参数
- finally的返回值
- 当finally中的回调函数返回的是失败的promise对象的时候,则finally返回失败状态的promis对象,值为回调函数返回promise对象的值
- 当finally的回调函数中出现报错,则finally直接返回失败的promise对象,值为错误信息
- 其他情况一律认为类似穿透
const promise = new Promise((resolve, reject) => {
// resolve(111);
// reject(222);
});
// promise变成成功/失败都触发,pending不触发
promise.finally(() => {
console.log("finally()");
});
7. Promise 练习
-
题目1
console.log(111); const promise = new Promise((resolve, reject) => { reject(); console.log(222); }); promise .then(() => { console.log(333); return new Promise((resolve) => { reject(); }); }) .catch(() => { console.log(444); }) .then(() => { console.log(555); return new Promise((reject, resolve) => { reject(); // resolve(); }); }) .catch(() => { console.log(666); throw new Error("报错了~"); }) .then(() => { console.log(777); throw new Error("报错了~"); }) .then(() => console.log(888)) .then(() => console.log(999)) .catch(() => console.log(101010)); console.log(111111);
-
练习2
/* 需求:setTimeout模拟发送请求 请求a数据,请求成功在请求b数据,请求成功在请求c数据 */ const promise = new Promise((resolve, reject) => { // 执行异步代码,请求a数据 setTimeout(() => { console.log("a数据ok"); resolve(); }, 1000); }); promise.then(() => { // 请求b数据 return new Promise((resolve, reject) => { setTimeout(() => { console.log("b数据ok"); resolve(); }, 2000); }); }).then(() => { // 请求c数据 return new Promise((resolve, reject) => { setTimeout(() => { console.log("c数据ok"); resolve(); }, 3000); }); }).then(() => { console.log('所有数据都请求完毕了~'); }) -
练习3
/* 需求: 同时请求三个数据,全部请求成功了,才OK,只要有一个失败,就失败 */ /* const promise = new Promise((resolve, reject) => { let successNum = 0; setTimeout(() => { console.log("a数据ok"); reject(); successNum++; if (successNum === 3) { resolve(); } }, 1000); setTimeout(() => { console.log("b数据ok"); successNum++; if (successNum === 3) { resolve(); } }, 2000); setTimeout(() => { console.log("c数据ok"); successNum++; if (successNum === 3) { resolve(); } }, 3000); }); promise .then(() => console.log("全部成功了~")) .catch(() => console.log("失败了~")); */ const promise1 = new Promise((resolve, reject) => { setTimeout(() => { console.log("a数据ok"); resolve(); }, 1000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { console.log("b数据ok"); reject(); }, 2000); }); const promise3 = new Promise((resolve, reject) => { setTimeout(() => { console.log("c数据ok"); resolve(); }, 3000); }); const promise = Promise.all([promise1, promise2, promise3]); promise .then(() => console.log("全部成功了~")) .catch(() => console.log("失败了~"));
8. Promise的静态方法
8.1 Promise.all
- Promise.all([promise1, ...])
- Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组
- 这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。
- 它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
8.2 Promise.allSettled
- 该
Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
8.3 Promise.race
Promise.race(iterable)方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
8.4 Promise.any
Promise.any()接收一个Promise可迭代对象,只要其中的一个promise成功,就返回那个已经成功的promise。如果可迭代对象中没有一个promise成功(即所有的promises都失败/拒绝),就返回一个失败的promise `和AggregateError类型的实例
8.5 Promise.resolve
-
快速得到一个成功状态的promise对象,值为value
-
如果value是一个promise对象,则resolve方法的返回的promise的状态和值跟随内部value的状态和值
8.6 Promise.reject
-
快速得到一个失败状态的promise对象,值为value
-
不管value是什么对象,都是这个失败的promise对象的值
9.综合练习
//1
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
//2
Promise.resolve("foo")
.then(Promise.resolve("hoo"))
.then((value) => {
console.log(value);
})
//3
Promise.resolve(1)
.then(() => {
return 2
})
.then(Promise.resolve(3))
.then(console.log)
//4
Promise.resolve(1)
.then(() => {
return 2
})
.then(() => {
return Promise.resolve(3)
})
.then(console.log)
//5
new Promise((resolve, reject) => {
reject(1)
})
.then(value => {
console.log('成功', value);
}, reason => {
console.log('失败', reason);
})
.then(value => {
console.log('成功', value);
}, reason => {
console.log('失败', reason);
})
.catch(reason => console.log('失败', reason))
//6
new Promise((resolve, reject) => {
reject(1)
})
.then(value => {
console.log('成功', value);
})
.then(value => {
console.log
