ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

从零开始一个完整的promise(附源码)

2021-07-01 17:30:04  阅读:230  来源: 互联网

标签:resolve tempItem MyPromise 从零开始 promise promiseArr reject data 源码


实现过程详细步骤,文档传送门

源码:

// 先定义三个状态变量
const PENDING = 'pending'
const REJECTED = 'rejected'
const FULFILLED = 'fulfilled'

class MyPromise {

  state = PENDING
  value = ''      // 向后传的value值
  callbacks = []  // 回调队列

  constructor(fn) {
    if (typeof fn !== "function") {
      throw new Error('参数必须是函数')
    }
    fn(this._resolve.bind(this), this._reject.bind(this))
  }

  static resolve(data) {
    return new MyPromise(resolve => {
      resolve(data)
    })
  }
  static reject(data) {
    return new MyPromise((resolve, reject) => {
      reject(data)
    })
  }

  static all(promiseArr) {
    if (!Array.isArray(promiseArr)) {
      throw new Error('参数必须是数组')
    }
    return new MyPromise((resolve, reject) => {
      const result = []
      const Arrlength = promiseArr.length
      let tempItem
      let resolveNums = 0  //记录fulfilled实例的个数
      for (let i = 0; i < Arrlength; i++) {
        tempItem = promiseArr[i]
        if (!(tempItem instanceof MyPromise)) {
          tempItem = MyPromise.resolve(tempItem)
        }
        tempItem.then((data) => {
          resolveNums++
          result[i] = data
          // 全部都变为fulfilled,返回
          if (resolveNums === Arrlength) {
            resolve(result)
          }
        }, (data) => {
          reject(data)
        })
      }
    })
  }


  static race(promiseArr) {
    if (!Array.isArray(promiseArr)) {
      throw new Error('参数必须是数组')
    }
    return new MyPromise((resolve, reject) => {
      const Arrlength = promiseArr.length
      let tempItem
      for (let i = 0; i < Arrlength; i++) {
        tempItem = promiseArr[i]
        if (!(tempItem instanceof MyPromise)) {
          tempItem = MyPromise.resolve(tempItem)
        }
        tempItem.then((data) => {
          resolve(data)
        }, (data) => {
          reject(data)
        })
      }
    })
  }

  static any(promiseArr) {
    if (!Array.isArray(promiseArr)) {
      throw new Error('参数必须是数组')
    }
    return new MyPromise((resolve, reject) => {
      const result = []
      const Arrlength = promiseArr.length
      let tempItem
      let rejectedNums = 0  //记录rejected实例的个数
      for (let i = 0; i < Arrlength; i++) {
        tempItem = promiseArr[i]
        if (!(tempItem instanceof MyPromise)) {
          tempItem = MyPromise.resolve(tempItem)
        }
        tempItem.then(data => {
          resolve(data)
        }, data => {
          result[i] = data
          if (++rejectedNums === Arrlength) {
            reject(result)
          }
        })
      }
    })
  }
  // 捕获前边未处理的reject。
  catch(onRejected) {
    return this.then(null, onRejected)
  }

  // 无论前边promise是何种状态,都会执行的方法
  finally(fn) {
    return this.then(fn, fn)
  }

  then(onFulfilled, onRejected) {
    const _this = this;   //_this指向前一个promise对象
    return new MyPromise((resolve, reject) => {
      _this._handle({
        onFulfilled,
        onRejected,
        resolve,
        reject
      })
    })
  }



  _resolve(value) {
    if (this.state !== PENDING) {
      return
    }
    this.state = FULFILLED  //修改状态
    this.value = value      // 赋值,用于向后传递
    this.callbacks.forEach(cb => this._handle(cb))  //回调then中的注册函数
  }

  _reject(error) {
    if (this.state !== PENDING) {
      return
    }
    this.state = REJECTED  //修改状态
    this.value = error      // 赋值,用于向后传递
    this.callbacks.forEach(cb => this._handle(cb))  //回调then中的注册函数
  }
  _handle(callback) {
    // prnding状态时,注册函数入栈
    if (this.state === PENDING) {
      this.callbacks.push(callback)
      return
    }
    // 按需获取then中注册的回调函数
    const cb = this.state === FULFILLED ? callback.onFulfilled : callback.onRejected

    // 改变then返回的promise的状态,持续回调后续的then
    const cb_changeState = this.state === FULFILLED ? callback.resolve : callback.reject

    let ret

    if (cb) {
      ret = cb(this.value) //计算继续向后传递的值
      // 返回一个promise
      if (ret instanceof MyPromise) {
        ret.then((data) => {
          callback.resolve(data)
        }, (err) => {
          callback.reject(err)
        })
      } else {
        callback.resolve(ret)
      }
    } else {
      cb_changeState(this.value) //then里没有回调函数,把当前value继续向下传递
    }
  }
}

标签:resolve,tempItem,MyPromise,从零开始,promise,promiseArr,reject,data,源码
来源: https://blog.csdn.net/u013910340/article/details/118391385

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有