1. 异步代码的困难
我们调用一个函数,这个函数中发送网络请求(我们可以用定时器来模拟),如果发送网络请求成功了,那么告知调用者发送成功,并且将相关数据返回过去,如果发送网络请求失败了,那么告知调用者发送失败,并且告知错误信息
在promise之前我们是使用回调函数
// 1.设计这样的一个函数
function execCode(counter, successCallback, failureCallback) {
// 异步任务
setTimeout(() => {
if (counter > 0) { // counter可以计算的情况
let total = 0
for (let i = 0; i < counter; i++) {
total += i
}
// 在某一个时刻只需要回调传入的函数
successCallback(total)
} else { // 失败情况, counter有问题
failureCallback(`${counter}值有问题`)
}
}, 3000)
}
// 2.ES5之前,处理异步的代码都是这样封装
execCode(100, (value) => {
console.log("本次执行成功了:", value)
}, (err) => {
console.log("本次执行失败了:", err)
})
2. promise的作用
new Promise((resolve, reject) => {
})
所以上面的困难我们可以通过promise解决
function execCode(counter) {
return new Promise((resolve, reject) => {
// 异步任务
setTimeout(() => {
if (counter > 0) { // counter可以计算的情况
let total = 0
for (let i = 0; i < counter; i++) {
total += i
}
// 成功的回调
resolve(total)
} else { // 失败情况, counter有问题
// 失败的回调
reject(`${counter}有问题`)
}
}, 3000)
})
}
// 执行一次
execCode(255).then(value => {
console.log("成功:", value)
}).catch(err => {
console.log("失败:", err)
})
3. promise基本使用
Executor是在创建Promise时需要传入的一个回调函数,这个回调函数会被立即执行,并且传入两个参数(resolve,reject)
Promise对象里的异步操作执行时有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),而Promise对象状态的改变,只有两种可能:从pending变为fulfilled或者从pending变为rejected
1. Promise的状态锁死
在我们调用resolve的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成fulfilled,在之后我们去调用reject时,已经不会有任何的响应了(并不是这行代码不会执行,而是无法改变Promise状态,因为他的状态已经变为fulfilled)
这里需要注意:一旦状态被确定下来(resolve或reject方法的第一次调用),Promise的状态会被锁死,该Promise的状态是不可更改的
// 1.创建一个Promise对象
const promise = new Promise((resolve, reject) => {
// 注意: Promise的状态一旦被确定下来, 就不会再更改, 也不能再执行某一个回调函数来改变状态
// 1.待定状态 pending
console.log("111111")
console.log("222222")
console.log("333333")
// 2.兑现状态 fulfilled
resolve()
// 3.拒绝状态 rejected
reject()
})
2. resolve不同值
◼ 情况一:如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数;
◼ 情况二:如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态:
const p = new Promise((resolve) => {
// setTimeout(resolve, 2000)
setTimeout(() => {
resolve("p的resolve")
}, 2000)
})
const promise = new Promise((resolve, reject) => {
// 如果resolve的值本身Promise对象, 那么当前的Promise的状态会有传入的Promise来决定
resolve(p)
})
promise.then(res => {
console.log("then中拿到结果:", res)
})
◼ 情况三:如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态
const promise = new Promise((resolve, reject) => {
resolve({
name: "kobe",
then: function(resolve) {
resolve(11111)
}
})
})
promise.then(res => {
console.log("then中拿到结果:", res)
})
3. then方法参数
const promise = new Promise((resolve, reject) => {
resolve("success")
// reject("failure")
})
// then参数的传递方法: 可以传递两个参数
promise.then(res => {
console.log("成功回调~", res)
}, err => {
console.log("失败回调~", err)
})
// 但是推荐这种写法
promise.then(res => {
}).catch(err => {
})
4. then方法的多次调用
一个Promise的then方法是可以被多次调用的,每次调用我们都可以传入对应的fulfilled回调,当Promise的状态变成fulfilled的时候,这些then回调函数都会被执行
const promise = new Promise((resolve, reject) => {
resolve("success")
})
promise.then(res => {
console.log("成功回调~", res)
})
promise.then(res => {
console.log("成功回调~", res)
})
promise.then(res => {
console.log("成功回调~", res)
})
promise.then(res => {
console.log("成功回调~", res)
})
5. then方法的返回值
then方法本身是有返回值的,它的返回值是一个Promise,所以我们可以进行链式调用
// Promise本身就是支持链式调用
// then方法是返回一个新的Promise, 链式中的then是在等待这个新的Promise有决议之后执行的
promise.then(res => {
// then方法是返回一个新的Promise, 这个Promise的决议是等到then方法传入的回调函数有返回值时, 进行决议
return "bbbbbbbb"
}).then(res => {
// res => bbbbbbbb
}).then(res => {
// res => undefined
return new Promise((resolve, reject) => {
resolve("aaaaaa")
})
}).then(res => {
// res => aaaaaa
})
6. catch方法多次调用
同理变化为rejected状态时,所有的catch回调都会执行
const promise = new Promise((resolve, reject) => {
reject("failure")
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
但是需要注意的是,下面这种情况会报错,因为then方法中没有失败的回调
const promise = new Promise((resolve, reject) => {
reject("failure")
})
promise.then(res => {
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
promise.catch(err => {
console.log("失败的回调:", err)
})
7.catch方法返回值
上catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法
const promise = new Promise((resolve, reject) => {
// reject("error: aaaaa")
resolve("aaaaaa")
})
// 1.catch方法也会返回一个新的Promise
promise.catch(err => {
console.log("catch回调:", err)
return "bbbbb"
}).then(res => {
console.log("then第一个回调:", res)
return "ccccc"
}).then(res => {
console.log("then第二个回调:", res)
})
8. catch方法的执行时机
当promise变为rejected的时候,会跳过then方法,找到最近的catch方法去执行
promise.then(res => {
console.log("then第一次回调:", res)
// throw new Error("第二个Promise的异常error")
return "bbbbbb"
}).then(res => {
console.log("then第二次回调:", res)
throw new Error("第三个Promise的异常error")
}).then(res => {
console.log("then第三次回调:", res)
}).catch(err => {
console.log("catch回调被执行:", err)
})
9. finally方法
示无论Promise对象无论变成fulfilled还是rejected状态,最终都会被执行的代码
const promise = new Promise((resolve, reject) => {
// pending
// fulfilled
resolve("aaaa")
// rejected
// reject("bbbb")
})
promise.then(res => {
console.log("then:", res)
// foo()
}).catch(err => {
console.log("catch:", err)
// foo()
}).finally(() => {
console.log("哈哈哈哈")
console.log("呵呵呵呵")
})
5.Promise类方法
1. resolve
// 实例方法
// const promise = new Promise((resolve) => {
// // 进行一系列的操作
// resolve("result")
// })
// promise.catch
// 类方法
const studentList = []
const promise = Promise.resolve(studentList)
promise.then(res => {
console.log("then结果:", res)
})
// 相当于
// new Promise((resolve) => {
// resolve("Hello World")
// })
2.reject
// 类方法
const promise = Promise.reject("rejected error")
promise.catch(err => {
console.log("err:", err)
})
// 相当于
// new Promise((_, reject) => {
// reject("rejected error")
// })
3. all
它的作用是将多个Promise包裹在一起形成一个新的Promise,新的Promise状态由包裹的所有Promise共同决定
✓ 当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;
✓ 当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2 resolve")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve")
}, 5000)
})
// all:全部/所有
Promise.all([p1, p2, p3]).then(res => {
console.log("all promise res:", res)
}).catch(err => {
console.log("all promise err:", err)
})
4. allSettled
该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是rejected时,才会有最终的状态;
并且这个Promise的结果一定是fulfilled的
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2 resolve")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve")
}, 5000)
})
// 类方法: allSettled
Promise.allSettled([p1, p2, p3]).then(res => {
console.log("all settled:", res)
})
5. race
表示多个Promise相互竞争,谁先有结果,那么就使用谁的结果
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1 resolve")
// reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p2 resolve")
reject("p2 reject error")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve")
}, 5000)
})
// 类方法: race方法
// 特点: 会等到一个Promise有结果(无论这个结果是fulfilled还是rejected)
Promise.race([p1, p2, p3]).then(res => {
console.log("race promise:", res)
}).catch(err => {
console.log("race promise err:", err)
})
6. any
any方法会等到一个fulfilled状态,才会决定新Promise的状态;
◼ 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态;
◼ 如果所有的Promise都是reject的,那么会报一个AggregateError的错误
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p2 resolve")
reject("p2 reject error")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p3 resolve")
reject("p3 reject error")
}, 5000)
})
// 类方法: any方法
Promise.any([p1, p2, p3]).then(res => {
console.log("any promise res:", res)
}).catch(err => {
console.log("any promise err:", err)
})