JS原理2(Promise)


1 Promise语法

	//resolve reject
	const promise = new Promise((resolve,reject) => {
		// 异步操作代码
		if ( /* 操作成功 */){
			resolve("success");
		}else{
			reject("error");
		}
	})
	
	//then catch
	promise.then(res => {
	    console.log(res);
	   }, err => {
	   	    console.log(err );
	   }).catch(function(e){
	    console.log(e);
	})
	
	const p1 = Promise.resolve(1)
	const p2 = Promise.reject(2)
	function p3(){
	    return  new Promise(function(resolve,reject){
	        resolve("3");
	    })
	}
	//all方法提供了并行执行异步操作的能力,在all中所有异步操作结束后执行回调。
	Promise.all([p1,p2,p3()]).then(function(data){
	    console.log(data);  //[1,2,'3']
	})
	//race 第一个promise返回的结果
	Promise.race([p1,p2,p3()]).then(function(data){
	    console.log(data);  //1
	})
	//any 第一个resolve返回的而己过
	Promise.any([p1,p2,p3()]).then(function(data){
	    console.log(data);  //1
	})

2 Promise原理

2.1 构造函数

  1. 定义类MyPromise,内部添加构造函数constructor,构造函数需要接收回调函数func
  2. 在构造函数中定义resolvereject
  3. 构造函数内部调用func并将resolvereject传入:func(resolve,reject)
    // 1. 定义类
    class MyPromise {
      // 2. 添加构造函数
      constructor(func) {
        // 3. 定义resolve/reject
        const resolve = (result) => {
          console.log('resolve-执行啦:', result)
        }
        const reject = (result) => {
          console.log('reject-执行啦:', result)
        }
    
        // 4. 执行回调函数
        func(resolve, reject)
      }
    }
    //调用
    const p = new MyPromise((resolve, reject) => {
      resolve('success')
      // reject('error')
    })
    

2.2 状态

  1. 定义3个常量用来保存状态,pendingfulfilledrejected
  2. MyPromise内部定义属性stateresult分别用来保存状态和原因
  3. 调用resolve时传入具体原因,如果状态为pending则更改状态并记录兑现原因
  4. 调用reject时传入具体原因,如果状态为pending则更改状态并记录拒绝原因
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 1. 添加状态
      state = PENDING
      // 2. 添加原因
      result = undefined
    
      constructor(func) {
        // 3. 调整resolve/reject
        // 4. 状态不可逆
        // 改状态: pending->fulfilled
        // 记录原因
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
          }
        }
        // 改状态: pending->rejected
        // 记录原因
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
          }
        }
    
        func(resolve, reject)
      }
    }
    //调用
    const p = new MyPromise((resolve, reject) => {
      resolve('success') // pending -> fulfilled
      // reject('error') // pending -> rejected
    })
    p.state // 状态
    p.result // 原因
    

2.3 then方法

  1. 添加then方法,接收2个回调函数

    1. 成功回调onFulfilled
    2. 失败回调onRejected
  2. 判断传入的onFulfilledonRejected是否为函数,如果不是设置默认值

  3. 根据状态调用onFulfilledonRejected并传入兑现或拒绝原因

    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 状态
      state = PENDING
      // 原因
      result = undefined
    
      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
          }
        }
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
          }
        }
        func(resolve, reject)
      }
    
      // 1. 添加实例方法
      then(onFulfilled, onRejected) {
        // 2. 参数判断(参考文档)
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
    
        // 2.1 执行成功回调
        // 2.2 执行失败回调
        if (this.state === FULFILLED) {
          onFulfilled(this.result)
        } else if (this.state === REJECTED) {
          onRejected(this.result)
        }
      }
    }
    //调用
    const p = new MyPromise((resolve, reject) => {
        resolve('success')
        // reject('error')
    })
    p.then(res => {
      console.log('成功回调:', res)
    }, err => {
      console.log('失败回调:', err)
    })
    

2.4 then方法 - 异步

  1. MyPromise添加私有属性#handlers

    1. 保存then方法调用时状态为pending的回调函数
    2. 格式为对象数组:[{onFulfilled,onRejected}...]
  2. 构造函数内部调整resolvereject的逻辑

    1. 调用resolve时取出数组#handlers中的所有onFulfilled回调函数进行调用
    2. 调用reject时取出数组#handlers中的所有onRejected回调函数进行调用
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 状态
      state = PENDING
      // 原因
      result = undefined
      // 1. 定义实例属性
      #handlers = [] // [{onFulfilled,onRejected}...]
    
      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            // 3. 调用成功回调
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            // 4. 调用失败回调
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }
        func(resolve, reject)
      }
    
      // then方法
      then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
    
        if (this.state === FULFILLED) {
          onFulfilled(this.result)
        } else if (this.state === REJECTED) {
          onRejected(this.result)
        } else if (this.state === PENDING) {
          // 2. 保存回调函数
          this.#handlers.push({
            onFulfilled, onRejected
          })
        }
      }
    }
    //调用
    const p = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        resolve('success')
        // reject('error')
      }, 2000);
    })
    p.then(res => {
      console.log('then1:', res)
    }, err => {
      console.log('then1:', err)
    })
    p.then(res => {
      console.log('then2:', res)
    }, err => {
      console.log('then2:', err)
    })
    

2.5 异步任务

vue2异步方法:Promise.then、MutationObserver 、 setImmediate 、 setTimeout
选用:queueMicrotask 、MutationObserver 、setTimeout
1. queueMicrotask :新式浏览器均支持,node11开始支持,ie不支持
2. MutationObserver :新式浏览器均支持,ie11开始支持
3. setImmediate:新式浏览器只有edge支持,ie10开始支持
4. setTimeout:浏览器支持,node支持
核心步骤:

  1. 封装执行异步任务的函数
    1. 定义函数传入异步任务(回调函数)
    2. 内部根据实际情况判断并使用开启异步任务的api即可,比如queueMicrotask,MutationObserver
    3. 调用的api可以根据实际情况进行调整
    4. 如果都无法执行,使用setTimeout兜底
  2. 调整then中的逻辑,fulFilledrejectedpending3种状态时的回调函数,使用封装的函数包装一次
// 1. 定义异步任务函数
function runAsynctask(callback) {
  // 2. 调用核心api(queueMicrotask,MutationObserver,setTimeout)
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof MutationObserver === 'function') {
    const obs = new MutationObserver(callback)
    const divNode = document.createElement('div')
    obs.observe(divNode, { childList: true })
    divNode.innerText = '12345'
  } else {
    setTimeout(callback, 0)
  }
}

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
  // 状态
  state = PENDING
  // 原因
  result = undefined
  // 回调函数数组
  #handlers = [] // [{onFulfilled,onRejected}...]

  // 构造函数
  constructor(func) {
    // pending->fulfilled
    const resolve = (result) => {
      if (this.state === PENDING) {
        this.state = FULFILLED
        this.result = result
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result)
        })
      }
    }
    // pending->rejected
    const reject = (result) => {
      if (this.state === PENDING) {
        this.state = REJECTED
        this.result = result
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result)
        })
      }
    }
    func(resolve, reject)
  }

  // then方法
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
    onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

    // 3. 使用封装函数
    if (this.state === FULFILLED) {
      runAsynctask(() => {
        onFulfilled(this.result)
      })
    } else if (this.state === REJECTED) {
      runAsynctask(() => {
        onRejected(this.result)
      })
    } else if (this.state === PENDING) {
      this.#handlers.push({
        onFulfilled: () => {
          runAsynctask(() => {
            onFulfilled(this.result)
          })
        }, onRejected: () => {
          runAsynctask(() => {
            onRejected(this.result)
          })
        }
      })
    }
  }
}

2.6 链式编程-fulfilled状态-返回值+异常

需求:

  1. then的链式编程

  2. 目前只考虑then的第一个回调函数

    1. 返回普通值
    2. 内部出现异常
    const p = new MyPromise ((resolve, reject) => {
      resolve(1)
    })
    p.then(res => {
      console.log(res)
      // throw 'throw-error'
      return 2
    }).then(res => {
      console.log(res)
    }, err => {
      console.log(err)
    })
    

核心步骤

  1. 链式编程的本质then方法会返回一个新的MyPromise对象

  2. 将原本的代码迁移到返回的MyPromise对象的回调函数中

  3. 内部通过try-catch捕获异常,出现异常通过reject传递异常

  4. 获取onFulfilled的执行结果,并通过resolve传递

    // 执行异步任务
    function runAsynctask(callback) {
      if (typeof queueMicrotask === 'function') {
        queueMicrotask(callback)
      } else if (typeof MutationObserver === 'function') {
        const obs = new MutationObserver(callback)
        const divNode = document.createElement('div')
        obs.observe(divNode, { childList: true })
        divNode.innerText = '12345'
      } else {
        setTimeout(callback, 0)
      }
    }
    
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 状态
      state = PENDING
      // 原因
      result = undefined
      // 回调函数数组
      #handlers = [] // [{onFulfilled,onRejected}...]
    
      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }
        func(resolve, reject)
      }
    
      then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
    
        // 1. 返回新Promise实例
        const p2 = new MyPromise ((resolve, reject) => {
          if (this.state === FULFILLED) {
            runAsynctask(() => {
              // 2. 获取返回值
              try {
                const x = onFulfilled(this.result)
                // console.log('x:', x)
                // 2.1 处理返回值
                resolve(x)
              } catch (error) {
                // 2.2 处理异常
                // console.log('捕获异常:', error)
                reject(error)
              }
            })
          }
          else if (this.state === REJECTED) {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
          else if (this.state === PENDING) {
            this.#handlers.push({
              onFulfilled: () => {
                runAsynctask(() => {
                  onFulfilled(this.result)
                })
              }, onRejected: () => {
                runAsynctask(() => {
                  onRejected(this.result)
                })
              }
            })
          }
    
        })
    
        return p2
      }
    }
    

2.7 链式编程-fulfilled状态-返回Promise

需求:

  1. then的链式编程
  2. 目前只考虑then的第一个回调函数
    1. 返回Promise
    const p = new MyPromise((resolve, reject) => {
      resolve(1)
    })
    p.then(res => {
      return new MyPromise((resolve, reject) => {
        resolve(2)
        // reject('error')
      })
    }).then(res => {
      console.log('p2:', res) // 2
    }, err => {
      console.log('p2:', err) // error
    })
    

核心步骤:

  1. 判断onFulfilled的执行结果是否为MyPromise实例
  2. 如果是的话调用返回值的then方法,获取兑现和拒绝的原因并通过resolvereject传递即可
    // 执行异步任务
    function runAsynctask(callback) {
      if (typeof queueMicrotask === 'function') {
        queueMicrotask(callback)
      } else if (typeof MutationObserver === 'function') {
        const obs = new MutationObserver(callback)
        const divNode = document.createElement('div')
        obs.observe(divNode, { childList: true })
        divNode.innerText = '12345'
      } else {
        setTimeout(callback, 0)
      }
    }
    
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 状态
      state = PENDING
      // 原因
      result = undefined
      // 回调函数数组
      #handlers = [] // [{onFulfilled,onRejected}...]
    
      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }
        func(resolve, reject)
      }
    
      // then方法
      then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
    
        const p2 = new MyPromise((resolve, reject) => {
          if (this.state === FULFILLED) {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                // 1.处理返回Promise
                if (x instanceof MyPromise) {
                  // console.log('MyPromise实例')
                  // 2. 调用then方法
                  // x.then(res => console.log(res), err => console.log(err))
                  x.then(res => resolve(res), err => reject(err))
                } else {
                  resolve(x)
                }
              } catch (error) {
                reject(error)
              }
            })
          }
          else if (this.state === REJECTED) {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
          else if (this.state === PENDING) {
            this.#handlers.push({
              onFulfilled: () => {
                runAsynctask(() => {
                  onFulfilled(this.result)
                })
              }, onRejected: () => {
                runAsynctask(() => {
                  onRejected(this.result)
                })
              }
            })
          }
        })
        return p2
      }
    }
    

2.8 链式编程-fulfilled状态-重复引用

需求:

  1. then中返回的then方法返回的Promise实例报错
    const p = new MyPromise((resolve, reject) => {
      resolve(1)
    })
    const p2 = p.then(res => {
      return p2
    })
    p2.then(
      res => { },
      err => console.log('err:', err))
    

核心步骤:

  1. 判断onFulfilled函数的返回值是否和then方法内部返回的MyPromise相同
  2. 如果相同抛出错误new TypeError('Chaining cycle detected for promise #<Promise>')
    // 执行异步任务
    function runAsynctask(callback) {
      if (typeof queueMicrotask === 'function') {
        queueMicrotask(callback)
      } else if (typeof MutationObserver === 'function') {
        const obs = new MutationObserver(callback)
        const divNode = document.createElement('div')
        obs.observe(divNode, { childList: true })
        divNode.innerText = '12345'
      } else {
        setTimeout(callback, 0)
      }
    }
    
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 状态
      state = PENDING
      // 原因
      result = undefined
      // 回调函数数组
      #handlers = [] // [{onFulfilled,onRejected}...]
    
      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }
        func(resolve, reject)
      }
    
      // then方法
      then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
    
        const p2 = new MyPromise((resolve, reject) => {
          if (this.state === FULFILLED) {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                // 1. 处理重复引用
                if (x === p2) {
                  // console.log('返回了p2')
                  // 2. 抛出错误 Chaining cycle detected for promise #<Promise>
                  throw new TypeError('Chaining cycle detected for promise #<Promise>')
                }
                if (x instanceof MyPromise) {
                  x.then(res => resolve(res), err => reject(err))
                } else {
                  resolve(x)
                }
              } catch (error) {
                reject(error)
              }
            })
          }
          else if (this.state === REJECTED) {
            runAsynctask(() => {
              onRejected(this.result)
            })
          }
          else if (this.state === PENDING) {
            this.#handlers.push({
              onFulfilled: () => {
                runAsynctask(() => {
                  onFulfilled(this.result)
                })
              }, onRejected: () => {
                runAsynctask(() => {
                  onRejected(this.result)
                })
              }
            })
          }
        })
        return p2
      }
    }
    

2.9 链式编程-rejected状态 pending状态

需求:

  1. then的第二个回调函数,执行reject时的链式编程
  2. then方法中pending状态时推入数组的函数增加try-catch捕获异常
  3. 获取推入数组的回调函数的返回值
  4. 调用封装的函数并传入获取的值
    const p = new MyPromise((resolve, reject) => {
      reject(1)
      // setTimeout(() => {
      //   resolve(1)
      // }, 2000)
    })
    const p2 = p.then(undefined, err => {
      throw 'error'
      // return p2
      // return 2
      // return new MyPromise((resolve, reject) => {
      //   resolve('MyPromise-2')
      // })
    })
    p2.then(res => {
      console.log('p2-res:', res)
    }, err => {
      console.log('p2-err:', err)
    })
    

核心步骤:

  1. 判断onRejected可能出现的异常,如果出现通过reject传递

  2. 获取onRejected函数的执行结果

  3. fulfilled状态时的处理逻辑抽取为函数,rejected状态时调用函数复用逻辑

    // 执行异步任务
    function runAsynctask(callback) {
      if (typeof queueMicrotask === 'function') {
        queueMicrotask(callback)
      } else if (typeof MutationObserver === 'function') {
        const obs = new MutationObserver(callback)
        const divNode = document.createElement('div')
        obs.observe(divNode, { childList: true })
        divNode.innerText = '12345'
      } else {
        setTimeout(callback, 0)
      }
    }
    
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class MyPromise {
      // 状态
      state = PENDING
      // 原因
      result = undefined
      // 回调函数数组
      #handlers = [] // [{onFulfilled,onRejected}...]
    
      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }
        func(resolve, reject)
      }
    
      then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
    
        const p2 = new MyPromise((resolve, reject) => {
          if (this.state === FULFILLED) {
            runAsynctask(() => {
              try {
                const x = onFulfilled(this.result)
                // 4. 调用函数
                resolvePromise(p2, x, resolve, reject)
                // if (x === p2) {
                //   throw new TypeError('Chaining cycle detected for promise #<Promise>')
                // }
                // if (x instanceof MyPromise) {
                //   x.then(res => resolve(res), err => reject(err))
                // } else {
                //   resolve(x)
                // }
              } catch (error) {
                reject(error)
              }
            })
          }
    
          else if (this.state === REJECTED) {
            runAsynctask(() => {
              // 1. 处理异常
              try {
                // 2. 获取返回值
                const x = onRejected(this.result)
                // console.log('x:', x)
                // 4. 调用函数
                resolvePromise(p2, x, resolve, reject)
              } catch (error) {
                reject(error)
              }
            })
          }
    
          else if (this.state === PENDING) {
            this.#handlers.push({
              onFulfilled: () => {
                runAsynctask(() => {
                   // 1. 处理异常
                  try {
                    // 2.获取返回值
                    const x = onFulfilled(this.result)
                    // 4.调用函数
                    resolvePromise(p2, x, resolve, reject)
                  } catch (error) {
                    reject(error)
                  }
                })
              }, onRejected: () => {
                runAsynctask(() => {
                   // 1. 处理异常
    				try {
    	               // 2.获取返回值
    	               const x = onRejected(this.result)
    	               // 4.调用函数
    	               resolvePromise(p2, x, resolve, reject)
    	             } catch (error) {
    	                reject(error)
    	             }
                })
              }
            })
          }
        })
    
        return p2
      }
    }
    
    // 3.抽取函数
    function resolvePromise(p2, x, resolve, reject) {
      if (x === p2) {
        throw new TypeError('Chaining cycle detected for promise #<Promise>')
      }
      if (x instanceof MyPromise) {
        x.then(res => resolve(res), err => reject(err))
      } else {
        resolve(x)
      }
    }
    

2.10 实例方法catch

需求

const p = new MyPromise((resolve, reject) => {
  reject('reject-error')
  // throw 'throw-error'
})
p.then(res => {
  console.log('res:', res)
}).catch(err => {
  console.log('err:', err)
})

核心步骤

  1. 定义catch方法,等同于:then(undefined,onRjected)

  2. 使用try-catch包裹constructor中的func捕获异常

      // 构造函数
      constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }
    
        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }
    
        // 2. 处理异常
        try {
          func(resolve, reject)
        } catch (error) {
          // console.log('error:', error)
          reject(error)
        }
      }
      
      catch(onRejected) {
        // 1. 内部调用then方法
        return this.then(undefined, onRejected)
      }
    

2.11 实例方法finally

需求:

  1. 无论成功失败都会执行finally的回调函数
  2. 回调函数不接受任何参数
    const p = new MyPromise((resolve, reject) => {
      // resolve('resolve-res')
      // reject('reject-error')
      // throw 'throw-error'
    })
    p.then(res => {
      console.log('res:', res)
    }).catch(err => {
      console.log('err:', err)
    }).finally(() => {
      console.log('finally')
    })
    

核心步骤

  1. 添加finally方法,接收最终执行的回调函数onFinally
  2. finally方法的本质为内部调用then方法
  3. 调用形式为第一个和第二个回调函数均传入onFinally即可
    finally(onFinally) {    
    	return this.then(onFinally,onFinally)
    }
    

2.12 静态方法resolve

需求
返回一个带有成功原因的Promise对象

MyPromise.resolve(new MyPromise((resolve, reject) => {
  // resolve('resolve')
  // reject('reject')
  // throw 'error'
})).then(res => {
  console.log('res:', res)
}, err => {
  console.log('err:', err)
})
MyPromise.resolve('xdk').then(res => {
  console.log(res)
})

核心步骤:

  1. 通过static关键字添加静态方法resolve,接收参数value
  2. 内部判断传入的值
    1. 如果是Promise实例,直接返回
    2. 其他的值,创建Promise实例并返回,内部通过resolve(value)传递value
      static resolve(value) {
        // 1. 判断传入值
        if (value instanceof MyPromise) {
          // 2.1 Promise直接返回
          return value
        }
        // 2.2 转为Promise并返回(fulfilled状态)
        return new MyPromise((resolve) => {
          resolve(value)
        })
      }
    

2.13 静态方法reject

需求:
返回一个带有拒绝原因的Promise对象

MyPromise.reject('error').catch(res => {
  console.log(res)
})

核心步骤:

  1. 添加静态方法reject并接收参数value
  2. 内部返回一个拒绝状态的Promise实例即可
  static reject(value) {
    // 1. 返回rejected状态的Promise
    // new MyPromise((resolve,reject)=>{
    return new MyPromise((undefined, reject) => {
      reject(value)
    })
  }

2.14 静态方法race

需求:

  1. 接收Promise数组,数组中第一个Promise敲定时,获取成功/失败结果
  2. 传入的参数不是数组,直接报错
const p1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 2000)
})
const p2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject(2)
  }, 1000)
})
MyPromise.race([p1, p2, 'xdk']).then((res) => {
  console.log('res:', res)
}, err => {
  console.log('err:', err)
})

核心步骤:

  1. 添加静态方法race接收参数promises
  2. 内部返回一个新的Promise实例,在返回的Promise实例中:
    1. 判断参数是否为数组,不是通过reject传递错误
    2. 遍历Promise数组,通过resolve静态方法等待每一个兑现
    3. 任何一个兑现,调用resolve传递兑现结果
    4. 任何一个拒绝,调用reject传递拒绝原因
  static race(promises) {
    // 1. 返回Promise
    return new MyPromise((resolve, reject) => {
      // 2. 判断是否为数组
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument is not iterable'))
      }
      // 3. 等待第一个敲定
      promises.forEach(p => {
        // p.then
        MyPromise.resolve(p).then(res => { resolve(res) }, err => { reject(err) })
      })
    })
  }

2.15 静态方法all

需求:
接收Promise数组

  1. 所有Promise都成功时,返回一个成功的Promise对象及成功数组
  2. 任何一个Promise失败,返回一个失败的Promise对象及第一个失败原因
const p1 = MyPromise.resolve(1)
const p2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(2)
    // reject('error')
  }, 1000)
})
const p3 = 3
MyPromise.all([p1, p2, p3]).then(res => {
  console.log('res:', res)
}, err => {
  console.log('err:', err)
})

核心步骤:

  1. 添加静态方法all
  2. 内部返回Promise实例,在返回的Promise实例中:
    1. 判断参数是否为数组,不是通过reject传递错误
    2. 空数组直接以空数组为结果进行兑现
    3. 遍历Promise数组,通过resolve静态方法等待结果
      1. 处理全部兑现:
        1. 通过数组记录结果,用索引的方式来添加,目的是保证结果的顺序和Promise数组的顺序一致
        2. 通过兑现次数进行判断,因为是通过索引的方式记录结果,如果第一次兑现的是最后一个,那么数组的长度就已经和Promise数组的长度一致了,所以需要通过兑现次数来进行判断
      2. 任意一个拒绝,调用reject传递拒绝原因
static all(promises) {
    // 1. 返回Promise实例
    return new MyPromise((resolve, reject) => {
      // 2. 判断是否为数组
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument is not iterable'))
      }
      // 3. 空数组直接兑现
      promises.length === 0 && resolve(promises)
      // 4.1 记录结果
      const results = []
      let count = 0
      promises.forEach((p, index) => {
        MyPromise.resolve(p).then(res => {
          // results.push 无法保证 结果的顺序和Promise数组的顺序一致
          // index 和 Promise实例的索引一致,保证顺序
          results[index] = res
          // 4.2 判断全部兑现
          count++
          count === promises.length && resolve(results)
        }, err => {
          // 5. 处理第一个拒绝
          reject(err)
        })
      })
    })
  }

2.16 静态方法allSettled

需求:

  1. 传入Promise数组,当所有对象都已敲定时
  2. 返回一个新的Promise对象及以数组形式保存的结果
const p1 = MyPromise.resolve(1)
const p2 = 2
const p3 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject(3)
  }, 1000)
})
MyPromise.allSettled([p1, p2, p3]).then(res => {
  console.log('res:', res)
}, err => {
  console.log('err:', err)
})

核心步骤:

  1. 添加静态方法allSettled
  2. 内部返回Promise实例,在返回的Promise实例中:
    1. 判断参数是否为数组,不是通过reject传递错误
    2. 空数组直接以空数组为结果进行兑现
  3. 遍历Promise数组,通过resolve静态方法等待敲定结果
  4. 等待全部敲定:并记录结果,根据兑现和拒绝将如下格式的内容通过索引的方式的记录到数组中
    1. 处理兑现:{state:FULFILLED,value:'xxx'}
    2. 处理拒绝:{state:REJECTED,reason:'xxx'}
  5. 根据敲定的次数判断是否全部敲定,全部敲定之后,通过resolve传递结果数组
  static allSettled(promises) {
    // 1. 返回Promise
    return new MyPromise((resolve, reject) => {
      // 2. 数组判断
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument is not iterable'))
      }
      // 3. 为空直接敲定
      promises.length === 0 && resolve(promises)

      // 4. 等待全部敲定
      // 4.1 记录结果
      const results = []
      let count = 0
      promises.forEach((p, index) => {
        MyPromise.resolve(p).then(res => {
          // 4.2 处理兑现{status:'fulfilled',value:''}
          results[index] = { status: FULFILLED, value: res }
          count++
          count === promises.length && resolve(results)
        }, err => {
          // 4.3 处理拒绝{status:'rejected',reason:''}
          results[index] = { status: REJECTED, reason: err }
          count++
          count === promises.length && resolve(results)
        })
      })
    })
  }

2.17 静态方法any

需求:
传入Promise数组,

  1. 任何一个Promise对象敲定时,返回一个新的Promise对象,及对应的结果
  2. 所有Promise都被拒绝时,返回一个包含所有拒绝原因的AggregateError错误数组
const p1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject(1)
  }, 2000)
})
const p2 = 2
const p3 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(3)
    // reject(3)
  }, 1000)
})
MyPromise.any([p1, p2, p3]).then(res => {
  console.log('res:', res)
}, err => {
  console.dir(err)
})

核心步骤:

  1. 添加静态方法any
  2. 内部返回Promise实例,在返回的Promise实例中:
    1. 判断参数是否为数组,不是通过reject传递错误
    2. 空数组直接以空数组为结果进行兑现
  3. 遍历Promise数组,通过resolve静态方法等待结果
    1. 第一个兑现,通过resolve传递兑现结果
    2. 全部拒绝:
      1. 定义数组,保存拒绝原因,通过索引记录,目的是保证顺序和Promise数组一致
      2. 通过次数判断是否全部拒绝,当全部拒绝时,通过reject传递AggregateError类型的错误,并将拒绝原因数组传递进去即可
  static any(promises) {
    // 1. 返回Promise,数组判断
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument is not iterable'))
      }
      // 2. 空数组直接拒绝
      promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'))

      // 3. 等待结果
      const errors = []
      let count = 0
      promises.forEach((p, index) => {
        MyPromise.resolve(p).then(res => {
          // 3.1 第一个兑现
          resolve(res)
        }, err => {
          // 3.2 全部拒绝
          errors[index] = err
          count++
          count === promises.length && reject(new AggregateError(errors, 'All promises were rejected'))
        })
      })
    })
  }

2.18 Promise\A+规范

  1. Promise\A+是社区推出的规范,最早Promise也是社区推出并实现的,旨在规范Promise的实现,里面约定了:

    1. 状态必须是pending,fulfilled,rejected
    2. then方法的详细实现细节
    3. 各种边界情况…
  2. 早期使用Promise需要导入第三方库,现在在新式浏览器中已经不需要导入第三方库,因为Promise是默认开启的

  3. 无论是早期实现了Promise的第三方库,以及现在的新式浏览器内置的Promise,都是符合Promise\A+规范要求的

参考资料

MDN-Promise

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值