什么是Promise?
Promise代表了一个尚未完成但预期将来会完成的异步操作的结果。它有三种状态:
- Pending(等待中) :初始状态,既不是成功,也不是失败状态。
- Fulfilled(已成功) :意味着操作成功完成。
- Rejected(已失败) :意味着操作失败。
并且状态一旦改变就不能再更改了。
构造函数
Promise的构造函数接受一个执行器(executor)函数作为参数,该函数接收两个函数resolve
和reject
作为参数。
例如我们平时使用的时候,实例化一个Promise对象
const p = new Promise((resolve, reject) => {
let random = Math.floor(Math.random() * 10);
if (random > 3) {
resolve('sucess')
} else {
reject('error')
}
})
结合Promise的三种状态,我们可以这样来设计构造函数
class myPromise {
constructor(executor) {
this.status = 'pending' // 初始状态
this.value = null // 存储成功值
this.reason = null // 存储失败原因
// 定义resolve函数
const resolve = (val) => {
if (this.state === 'pending') {
this.status = 'fulfilled'
this.value = val
}
}
// 定义reject函数
const reject = (error) => {
if (this.state === 'pending') {
this.status = 'rejected';
this.reason = error
}
}
executor(resolve, reject)
}
}
then和catch方法
Promise的then
方法用于添加成功和失败的回调函数,并返回一个新的Promise对象以支持链式调用。
Promise
的 then
方法接受两个可选的参数:onFulfilled
和 onRejected
。这两个参数分别是当 Promise
被解决(fulfilled)或拒绝(rejected)时调用的函数。
参数
- onFulfilled (可选): 当
Promise
成功解决时调用的函数。该函数接收Promise
解决时的值作为参数。 - onRejected (可选): 当
Promise
被拒绝时调用的函数。该函数接收Promise
拒绝的原因(reason)作为参数。
catch
方法是 Promise
链中用于错误处理的关键部分。它接收一个参数,即一个函数,这个函数会在 Promise
被拒绝时调用。这个函数接收一个参数,即拒绝的原因(reason)。
参数
- onRejected (函数): 当
Promise
被拒绝时调用的函数。该函数接收拒绝的原因(reason)作为参数。
使用
p
.then(res => {
console.log(res);
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
设计then和catch方法
then(onFulfilled) {
if (this.status === 'fulfilled') {
onFulfilled(this.value)
}
}
catch(onRejected){
if (this.status == 'rejected') {
onRejected(this.reason)
}
}
}
但是这种方法不能实现链式调用,就是不能连着使用then方法。 但是如果我想实现出这个模式,我们应该在then方法下回一个对象,而这个对象正常来讲就是this。
所以我们可以直接返回this吗,看下面这个情况。
p
.then(res => {
console.log(res);
return new Promise((resolve, reject) => {
resolve('1111')
})
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
在then方法下如果返回了一个新的promise的话,我们就不能直接在then方法里面直接返回this了。
所以我们应该先判断then的回调函数是否返回了新的对象,如果没有才返回当前then的this对象。
then(onFulfilled) {
let res
if (this.status === 'fulfilled') {
res = onFulfilled(this.value)
}
return res || this
}
catch(onRejected){
let rej
if (this.status == 'rejected') {
rej = onRejected(this.reason)
}
return rej || this
}
解决异步问题
上面的代码,似乎看着没有什么问题了,但是如果我这么写的话:
let p = new Mypromise((resolve, reject) => {
setTimeout(() => {
reject('p resolve')
}, 1000);
})
如果在Promise(假设为p)的then
方法被调用时,定时器(即Promise所依赖的异步操作)还没有完成,那么Promise的状态将保持为pending,并且then
中指定的回调函数不会立即执行。 为了解决这种情况,通常不会直接在Promise的创建过程中(即在new Promise(...)
内部)就执行then
方法中提供的回调函数,而是将这些回调函数保存起来,等到异步操作完成后再调用它们。
因此,我们需要用数组去存储成功和失败的回调函数
需要改造构造函数
constructor(executor) {
this.status = 'pending' // 初始状态
this.value = null // 存储成功值
this.reason = null // 存储失败原因
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
// 定义resolve函数
const resolve = (val) => {
if (this.state === 'pending') {
this.status = 'fulfilled'
this.value = val
this.onFulfilledCallbacks.forEach((fn)=>{
fn(this.value)
})
}
}
// 定义reject函数
const reject = (error) => {
if (this.state === 'pending') {
this.status = 'rejected';
this.reason = error
this.onRejectedCallbacks.forEach((fn)=>{
fn(this.reason)
})
}
}
executor(resolve, reject)
}
同时修改then和catch方法
then(onFulfilled) {
if (this.status === 'pending'){
this.onFulfilledCallbacks.push(onFulfilled)
}
let res
if (this.status === 'fulfilled') {
res = onFulfilled(this.value)
}
return res || this
}
catch(onRejected){
if (this.status === 'pending'){
this.onRejectedCallbacks.push(onRejected)
}
let rej
if (this.status == 'rejected') {
rej = onRejected(this.reason)
}
return rej || this
}
完整代码
class myPromise {
constructor(executor) {
this.state = 'pending'
this.value = null
this.reason = null
this.onResCallbacks = []
this.onRejCallbacks = []
const resolve = (val) => {
if (this.state === 'pending') {
this.state = 'fufilled'
this.value = val
this.onResCallbacks.forEach((fn) => {
fn(this.value)
})
}
}
const reject = (err) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = err
this.onRejCallbacks.forEach((fn) => {
fn(this.reason)
})
}
}
executor(resolve, reject)
}
then(onFufilled) {
if (this.state === 'pending') {
this.onResCallbacks.push(onFufilled)
}
let res
if (this.state === 'fufilled') {
res = onFufilled(this.value)
}
return res || this
}
catch(onRejected) {
if (this.state === 'pending') {
this.onRejCallbacks.push(onRejected)
}
let rej
if (this.state === 'rejected') {
rej = onRejected(this.reason)
}
return rej || this
}
}
const p = new myPromise((res,rej)=>{
res(1)
}).then((data)=>{
console.log(data);
})