Promise principle understanding

Promise

1. Basic structure:

const promise = new Promise(handler)

handler:(resolve, reject) => {}

promise.then(onFulfilled, onRejected).then(onFulfilled, onRejected)

2. Status:

Promise has three states

  • pending

  • fulfilled

  • rejected

The status can only be Pendingchanged Fulfilledor Pendingfrom Rejected, and the status will not change after the status is changed, and will remain in this status.

handlerThe function resolvecontains rejecttwo parameters and , which are two functions that can be used to change the state Promiseof and pass Promisein the value of

3. Points to pay attention to when conceiving the source code:

For handler: handler must be a function and needs to do type judgment if it is not a function type, an error will be thrown

For resolve and reject: two things need to be done, one is state modification, the other is value transfer, and care must be taken to ensure that the function can only be executed once

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
}

For then and its parameters onFulfilled and onRejected:

  1. When the state changes after resolve or reject is executed, then and the internal corresponding onFulfilled or onRejected will be executed

  2. Note that onFulfilled and onRejected must be functions or they will be ignored

  3. then() will return a promise which is the basis of the chain call

  4. The onFulfilled or onRejected in then needs to have a return value to make the onFulfilled or onRejected parameter in the next then have a value, and if there is no return value, it is undefined

  5. If onFulfilled or onRejected has a return value

    1. If the return value is not a Promise: the then of the next promise will be executed immediately (the status is fulfilled) and the returned value will be used as the parameter of onFulfilled or onRejected in this then

      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执行完会立即执行
      })

    2. If the return value is a Promise: the returned promise is equivalent to the next promise, and then of the next promise will be executed after the state of the return value changes, and the parameters of onFulfilled or onRejected in then are also passed in the returned promise

      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. Simple 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.The perfection of then

The simple version of the appeal is just the most basic prototype of promise, which will be improved below

Perfect point 1:

If the resolve or reject function in the handler is wrapped in an asynchronous method, then will be executed first and then resolve or reject will be executed (the status is still pending at this time, so the callback in then will not be executed)

Amended as follows:

// 新增两个变量用来存储回调函数
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()
    })
}

Perfect point 2:

Complete the chain call of then, corresponding to points 2, 3, 4, and 5 that need to be noted above

MyPromise.prototype.then(onFulfilled, onRejected) {
    // 对应第3点返回新的promise实例以实现链式调用
    return promise2 = new MyPromise((resolve, reject) => {
        // 需要注意 修正后的回调不仅会执行自己promise的回调 还会干预所返回的promise的状态
        
        // 修正后的成功回调
        fixedOnfulfilled(value) {
            // 执行自己promise的回调看是否报错 如果报错直接修改下一个promise的状态为rejected
			try {
				// 判断自己promise的回调是否为函数 不是函数直接传递值给下一个promise(对应第2点)
                if(!isFunction(onFulfilled)) {
					resolve(value)
                }else {
					let res = onFulfilled(value) // 执行自己的回调并收集返回值
                    // 判断返回值是否为promise 对应第5点
                    if(res instanceof MyPromise) {
						// 返回值是promise
                        // 这里不太好理解 实际是相当于将下一个promise的resolve和reject当作返回promise(res)的回调 执行返回promise回调的同时 修改下一个promise的状态 具体传递的值 是由返回promise内部决定的
                        res.then((v) => {resolve(v)}, (err) => {reject(err)}
                    }else{
                        // 返回值不是promise
                        resolve(res)
                    }
                }
                
            }catch(err) {
                // 修改下一个promise的状态为rejected
				reject(err)
            }
        }
        
        // 修正后的失败回调
        fixedOnRejected(err) {
            // 执行自己promise的回调看是否报错 如果报错直接修改下一个promise的状态为rejected
			try {
				// 判断自己promise的回调是否为函数 不是函数直接传递值给下一个promise(对应第2点)
                if(!isFunction(onRejected)) {
					reject(err)
                }else {
					let res = onRejected(err) // 执行自己的回调并收集返回值
                    // 判断返回值是否为promise 对应第5点
                    if(res instanceof MyPromise) {
						// 返回值是promise
                        // 这里不太好理解 实际是相当于将下一个promise的resolve和reject当作返回promise(res)的回调 执行返回promise回调的同时 修改下一个promise的状态 具体传递的值 是由返回promise内部决定的
                        res.then((v) => {resolve(v)}, (err) => {reject(err)}
                    }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(() => {
                    fixedOnfulfilled(this.resolveValue)
                })
                this.onRejectedList.push(() => {
                    fixedOnRejected(this.rejectValue)
                })
            }
    	}
    })
}

Perfect point 3:

asynchronous correction

The callback function in then is executed asynchronously

switch(this.status){
	case 'FULFILLED':{
        // 将成功回调放入事件队列中
        setTimeOut(() => {
			fixedOnfulfilled(this.resolveValue)
        })
        break
    }
    case 'REJECTED':{
        // 将失败回调放入事件队列中
        setTimeOut(() => {
			fixedOnRejected(this.rejectValue)
        })
        break
    }
    case 'PENDING': {
        this.onFulfilledList.push(() => {
            fixedOnfulfilled(this.resolveValue)
        })
        this.onRejectedList.push(() => {
            fixedOnRejected(this.rejectValue)
        })
    }
}

resolve and reject are executed at the end of the event loop, so async needs to be added as well

resolve(val) {
    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. Final code

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(() => {
           		    fixedOnfulfilled(this.resolveValue)
        		})
        		this.onRejectedList.push(() => {
            		fixedOnRejected(this.rejectValue)
        		})
    		}
		}
    })
}

Guess you like

Origin blog.csdn.net/m0_64023259/article/details/123463359