zoukankan      html  css  js  c++  java
  • 基于PromiseA+规范实现一个promise

    实现如果下规范的promise
    Aplus规范
    1,promise是一个类:有三个状态 pending/等待态 fulfilled/成功态 rejected/失败态
    2,promise默认执行器立即执行
    3,Promise的实例都有一个then方法
    4,执行器中用户可以自己决定成功或者失败,并且传入成功或者失败的原因
    5,如果excutor执行器函数发生异常的时候也会执行失败的逻辑
    6,如果Promise一旦进入成功态就不能再变为失败态,反之亦然
     
    // 定义promise三种状态
    let PENDING = 'PENDING'
    let RESOLVED = 'RESOLVED' // 成功状态
    let REJECTED = 'REJECTED'  // 失败状态
    console.log('own')
    
    const resolvePromise = (promise2, x, resolve, reject) => {
      // A+规范中  x和promise2引用同一个对象抛出类型错误
      if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
      }
      // 后续的条件要严格判断   保证代码能和别的库一起使用 
      // x可能是一个函数或者对象
      if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
        try {
          let then = x.then;
          if (typeof then === 'function') {
            // 只能判断then是函数就认为其是promise
            then.call(x, y => {
              resolve(y)
            }, e => {
              reject(e)
            })
          } else {
            resolve(x)
          }
        } catch (e) {
          //TODO handle the exception
        }
    
      } else {
        resolve(x)
      }
    }
    
    class Promise {
      constructor(excutor) {
        this.status = PENDING
        // 成功和失败的原因需要保存
        this.value = undefined; // 成功的值
        this.reason = undefined; // 失败的值
        this.onResolvedCallbacks = [];  // 存储成功的回调函数数组
        this.onRejectedCallbacks = [];  // 存储失败的回调函数数组
        // 只有等待态的时候才能更改状态
    
    
        let resolve = (value) => {
    
          if(value instanceof Promise){
            value.then(resolve,reject)  // 判断是promise.resolve 中如果传promise 递归解析 ,有延迟效果
          }
    
          if (this.status = PENDING) {
            this.value = value;
            this.status = RESOLVED;
            this.onResolvedCallbacks.forEach(fn => fn())
          }
    
        }
        let reject = (reason) => {
          if (this.status = PENDING) {
            this.reason = reason;
            this.status = REJECTED;
            this.onRejectedCallbacks.forEach(fn => fn())
          }
        }
        // 当函数发生异常直接抛出错误
        try {
          excutor(resolve, reject)
        } catch (e) {
          reject(e)
        }
      }
      // 关于then方法: 
      // 1: promise 成功或者失败会传递到外层的下一个then方法
      // 2: 返回的是普通值(除了promise之外的值)都会触底到下一then的成功中;出错的情况走到下一次的失败中;
      // 3: 错误处理 。自己最近的then没有错误处理,会向下传递错误直到有错误处理
      // 4: 每次执行完then 返回都是新的promise (一旦成功或者失败就不能够修改状态)
      then (onFulfilled, onRejected) {
    
        // 如果then中返回一个promise 我需要用x来决定是决定promise返回成功还是失败
    
        let promise2 = new Promise((resolve, reject) => {  // 链式调用
          if (this.status === RESOLVED) {
            setTimeout(() => { // 为了让resolvePromise拿到promise2
              try {
                // 如果状态是成功了,需要调用传入的第一个onFulfilled函数
                let x = onFulfilled(this.value)  //成功的回调直接执行;执行完成后拿到结果;ps: 成功之后返回的直接执行拿到结果存放到x中 
                // 但是返回的promise 还能继续then,继续传递成功的结果
                // x可能是promise,解析promise ,使用这个返回的结果决定下一个then是成功还是失败
                resolvePromise(promise2, x, resolve, reject) // 调用了下一个promise的resolve  
              } catch (error) {
                reject(error)
              }
    
            }, 0)
          }
          if (this.status === REJECTED) {
            setTimeout(() => { // 为了让resolvePromise拿到promise2
              try {
                // 如果状态失败了,就需要使用第二个函数讲失败的原因返回
                let x = onRejected(this.reason)
                // 处理失败
                resolvePromise(promise2, x, resolve, reject) //普通值都会传递到下一个的成功
              } catch (error) {
                reject(error)
              }
    
            }, 0)
          }
          // 调用then的时候可能是pending状态
          if (this.status === PENDING) {
            this.onResolvedCallbacks.push(() => {
              // todo
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value)
                  resolvePromise(promise2, x, resolve, reject)
                } catch (error) {
                  reject(error)
                }
              }, 0)
    
            })
            this.onRejectedCallbacks.push(() => {
              // todo
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason)
                  resolvePromise(promise2, x, resolve, reject);
                } catch (error) {
                  reject(error)
                }
              }, 0)
            })
          }
        })
        return promise2;
      }
      catch(errCallBack){
        return this.then(null,errCallBack)
      }
      static resolve(data){
        // 快速创建一个成功的promise
        return new Promise((resolve,reject) => {
          resolve(data)
        })
      }
      static reject(reason){
        // 快速创建一个失败的promise
        return new Promise((resolve,reject) => {
          reject(reason)
        })
      }
    }
  • 相关阅读:
    Js实现继承的几种方式
    ES6-promise实现异步请求
    CSS重排和重绘
    jq在元素的后面插入内容
    yii2 Query Builder 查询打印sql语句
    js replace(a,b)替换指定字符
    linux 打印当前工作目录
    linux 查看磁盘空间
    linux查看大文件
    js-Cannot read property 'innerHTML' of null
  • 原文地址:https://www.cnblogs.com/qqfontofweb/p/13258064.html
Copyright © 2011-2022 走看看