1.基本结构:
const promise = new Promise(handler)
handler:(resolve, reject) => {}
promise.then(onFulfilled, onRejected).then(onFulfilled, onRejected)
2.状态:
promise
存在三种状态
- Pending
- Fulfilled
- Rejected
状态只能由 Pending
变为 Fulfilled
或由 Pending
变为 Rejected
,且状态改变之后不会在发生变化,会一直保持这个状态。
handler
函数包含 resolve
和 reject
两个参数,它们是两个函数, Promise
的状态正是由这两个函数更改的。
3.构思源码需要注意的点:
handler
:handler
必须是函数 需要做类型判断 非函数类型则抛出错误
resolve
&reject
:需要做两件事,一个是状态修改,另一个是值的传递,另外需要注意确保函数只能执行一次
resolve(val) {
if(this.status !== 'PENDING') return // 确保只能执行一次
this.status = 'FULFILLED' // 状态修改
this.value = val // 收集传进来的值
}
reject(err) {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.value = err
}
对于then
以及其参数onFulfilled
和onRejected
:
- 当
resolve
或reject
执行后状态发生了改变才会执行then
以及内部对应的onFulfilled
或者onRejected
- 需要注意
onFulfilled
和onRejected
必须是函数,否则会被忽略 - 执行
then
后会返回一个promise实例,这个是链式调用的基础 then
中的onFulfilled
或者onRejected
如果有返回值,那么下一个then
中的onFulfilled
或者onRejected
可以通过参数获取到上一个promise实例的返回值,没有返回值则参数为undefinedonFulfilled
或者onRejected
有返回值又会分为两种情况
- 如果返回值不是Promise :下一个promise的then中的回调会立即执行(状态为fulfilled),可以通过回调的参数获取返回值,这里可能不太好理解,请看下面的例子,这里我们说的回调其实也就是
onFulfilled
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
promise2 = promise1.then(res => {
console.log('promise1的状态变为fulfilled') // 1s后执行
return '这是给promise2的'
})
promise2.then(res => {
console.log(res) // 打印 这是给promise2的 在promise1的then执行完会立即执行
})
- 如果返回值是Promise:这里很容易由理解误区,这里的这个返回值并不会作为链式调用所返回的下一个promise,也就是说下面的promise2其实并不是这个返回值,而是另外一个promise。但这个返回值状态的变化会直接影响链式调用所返回promise(也就是下面的promise2)的状态。(不理解可以后面的代码会解释)
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("这是传给promise1的");
}, 1000);
});
let promise2 = promise1.then((res) => {
console.log(res, "promise1的回调执行拉"); // 1s后执行
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("这是传给promise2的");
}, 2000);
});
});
promise2.then((res) => {
console.log(res, "promise2的回调执行拉"); // 在promise1的then执行完2s后执行 打印 这是传给promise2的, promise2的回调执行拉
});
4.简易版Promise
class MyPromise{
const isFunction = variable => typeof variable === 'function'
constructor(handler) {
// handler必须是函数 否则抛错
if (!isFunction(handle)) {
throw new Error('MyPromise must accept a function as a parameter')
}
// 首先声明变量用来存储状态以及传递的值
this.status = 'PENDING'
this.resolveValue = undefined
this.rejectValue = undefined
// 这两个数组后面解释其作用
this.onFulfilledList = []
this.onRejectedList = []
// 定义resolve以及reject
resolve(val) {
if(this.status !== 'PENDING') return // 确保只能执行一次resolve或者reject
this.status = 'FULFILLED' // 状态修改
this.resolveValue = val // 收集传进来的值
}
reject(err) {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
}
// 执行handler
try{
/*
* 注意:易错点 这里必须通过bind对resolve和reject的this绑定为此promise实例
* 否则在resolve和reject内部无法通过this获取到此promise实例的status和resolveValue/rejectValue
*/
handler(this.resolve.bind(this), this.reject.bind(this))
}catch(err){
this.reject(err)
}
}
}
// 定义then
MyPromise.prototype.then(onFulfilled, onRejected) {
switch(this.status){
case 'FULFILLED':{
onFulfilled(this.resolveValue)
}
case 'REJECTED':{
onRejected(this.rejectValue)
}
}
}
5.then的完善
上述简易版只是最基本的promise
雏形,下面将对其进行完善
完善点1:
如果handler
中的resolve
或者reject
函数被包裹在异步方法中,会出现未执行resolve
或者reject
直接执行该promise
的then
方法的情况,而没有执行resolve
或者reject
该promise
的状态就不会改变,状态仍然是PENDING
,我们需要对这种情况进行处理。(记得我们上面定义的两个数组么,要派上用场了)
修正如下:
// 新增两个变量用来存储回调函数
this.onFulfilledList = []
this.onRejectedList = []
// then的修正
MyPromise.prototype.then(onFulfilled, onRejected) {
switch(this.status){
case 'FULFILLED':{
onFulfilled(this.resolveValue)
break
}
case 'REJECTED':{
onRejected(this.rejectValue)
break
}
// 将回调都存储到回调数组里面
case 'PENDING': {
this.onFulfilledList.push(() => {
onFulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
onRejected(this.rejectValue)
})
}
}
}
// resolve和reject的修正
resolve(val) {
if(this.status !== 'PENDING') return // 确保只能执行一次resolve或者reject
this.status = 'FULFILLED' // 状态修改
this.resolveValue = val // 收集传进来的值
// 执行回调
this.onFulfilledList.forEach((cb) => {
cb()
})
}
reject(err) {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
// 执行回调
this.onRejectedList.forEach((cb) => {
cb()
})
}
完善点2:
完成then
的链式调用。这里逻辑有些复杂,请仔细看注释,多看几遍加深理解。
MyPromise.prototype.then(onFulfilled, onRejected) {
// 返回新的promise实例以实现链式调用
return promise = new MyPromise((resolve, reject) => {
// 修正后的成功回调
fixedOnfulfilled(value) {
// 执行自己promise的回调看是否报错 如果报错直接修改下一个promise的状态为rejected
try {
// 判断自己promise的回调是否为函数 不是函数直接传递值给下一个promise
if(!isFunction(onFulfilled)) {
resolve(value)
}else {
let res = onFulfilled(value) // 执行自己的回调并收集返回值
// 判断返回值是否为promise实例
if(res instanceof MyPromise) {
/*
* 返回值是promise实例
* 这里需要让我们返回promise的状态和回调返回promise的状态相同
* 把我们返回promise的resolve和reject 当作回调返回promise状态改变后的回调函数即可
* 即res的状态变为fulfilled后执行我们返回promise的resolve 变为rejected后执行reject
*/
res.then(resolve, reject)
}else{
// 返回值不是promise实例,直接将返回promise的状态改为fulfilled
resolve(value)
}
}
}catch(err) {
// 直接将返回promise的状态改为rejected
reject(err)
}
}
// 修正后的失败回调
fixedOnRejected(err) {
// 执行自己promise的回调看是否报错 如果报错直接修改下一个promise的状态为rejected
try {
// 判断自己promise的回调是否为函数 不是函数直接传递值给下一个promise
if(!isFunction(onRejected)) {
reject(err)
}else {
let res = onRejected(err) // 执行自己的回调并收集返回值
// 判断返回值是否为promise
if(res instanceof MyPromise) {
// 返回值是promise
res.then(resolve, reject)
}else{
// 返回值不是promise
reject(err)
}
}
}catch(err) {
// 修改下一个promise的状态为rejected
reject(err)
}
}
// 根据状态执行修正后的回调
switch(this.status){
case 'FULFILLED':{
fixedOnfulfilled(this.resolveValue)
break
}
case 'REJECTED':{
fixedOnRejected(this.rejectValue)
break
}
// 将回调都存储起来
case 'PENDING': {
this.onFulfilledList.push(() => {
onFulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
onRejected(this.rejectValue)
})
}
}
})
}
完善点3:
异步修正
我们在一个promise内部调用resolve
后同步执行一行代码,可以发现这行代码执行优先度仍然高于resolve函数内部的代码。所以我们可以推断resolve
和reject
内部代码并非同步代码。
resolve(val) {
// 用setTimeOut包裹一层以实现异步
setTimeOut(() => {
if(this.status !== 'PENDING') return // 确保只能执行一次resolve或者reject
this.status = 'FULFILLED' // 状态修改
this.resolveValue = val // 收集传进来的值
// 执行回调
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
reject(err) {
setTimeOut(() => {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
// 执行回调
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
6.最终代码
class MyPromise{
const isFunction = variable => typeof variable === 'function'
constructor(handler) {
if (!isFunction(handle)) {
throw new Error('MyPromise must accept a function as a parameter')
}
this.status = 'PENDING'
this.resolveValue = undefined
this.rejectValue = undefined
this.onFulfilledList = []
this.onRejectedList = []
resolve(val) {
setTimeOut(() => {
if(this.status !== 'PENDING') return
this.status = 'FULFILLED'
this.resolveValue = val
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
reject(err) {
setTimeOut(() => {
if(this.status !== 'PENDING') return
this.status = 'REJECTED'
this.rejectValue = err
this.onFulfilledList.forEach((cb) => {
cb()
})
})
}
try{
handler(this.resolve.bind(this), this.reject.bind(this))
}catch(err){
this.reject(err)
}
}
}
MyPromise.prototype.then(onFulfilled, onRejected) {
return promise2 = new MyPromise((resolve, reject) => {
fixedOnfulfilled(value) {
try {
if(!isFunction(onFulfilled)) {
resolve(value)
}else {
let res = onFulfilled(value)
if(res instanceof MyPromise) {
res.then(resolve, reject)
}else{
resolve(value)
}
}
}catch(err) {
reject(err)
}
}
fixedOnRejected(err) {
try {
if(!isFunction(onRejected)) {
reject(err)
}else {
let res = onRejected(err)
if(res instanceof MyPromise) {
res.then(resolve, reject)
}else{
reject(err)
}
}
}catch(err) {
reject(err)
}
}
switch(this.status){
case 'FULFILLED':{
setTimeOut(() => {
fixedOnfulfilled(this.resolveValue)
})
break
}
case 'REJECTED':{
setTimeOut(() => {
fixedOnRejected(this.rejectValue)
})
break
}
case 'PENDING': {
this.onFulfilledList.push(() => {
onFulfilled(this.resolveValue)
})
this.onRejectedList.push(() => {
onRejected(this.rejectValue)
})
}
}
})
}