zoukankan      html  css  js  c++  java
  • 请手写代码实现一个promise

    第一步:promise的声明

    class Promise{
      // 构造器
      constructor(executor){
        // 成功
        let resolve = () => { };
        // 失败
        let reject = () => { };
        // 立即执行
        executor(resolve, reject);
      }
    }

    第二步:三个基本状态(pending、fulfilled、rejected)

    class Promise{
      constructor(executor){
        // 初始化state为等待态
        this.state = 'pending';
        // 成功的值
        this.value = undefined;
        // 失败的原因
        this.reason = undefined;
        let resolve = value => {
          // state改变,resolve调用就会失败
          if (this.state === 'pending') {
            // resolve调用后,state转化为成功态
            this.state = 'fulfilled';
            // 储存成功的值
            this.value = value;
          }
        };
        let reject = reason => {
          // state改变,reject调用就会失败
          if (this.state === 'pending') {
            // reject调用后,state转化为失败态
            this.state = 'rejected';
            // 储存失败的原因
            this.reason = reason;
          }
        };
        // 如果executor执行报错,直接执行reject
        try{
          executor(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
    }

    第三步:then方法(两个参数:onFulfilled,onRejected)

    onFulfilled,onRejected如果他们是函数,

    则必须分别在fulfilled,rejected后被调用,value或reason依次作为他们的第一个参数

    class Promise{
      constructor(executor){...}
      // then 方法 有两个参数onFulfilled onRejected
      then(onFulfilled,onRejected) {
        // 状态为fulfilled,执行onFulfilled,传入成功的值
        if (this.state === 'fulfilled') {
          onFulfilled(this.value);
        };
        // 状态为rejected,执行onRejected,传入失败的原因
        if (this.state === 'rejected') {
          onRejected(this.reason);
        };
      }
    }

    第四步:异步的实现

    当resolve在setTomeout内执行,then时state还是pending等待状态

    我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们

    class Promise{
      constructor(executor){
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        // 成功存放的数组
        this.onResolvedCallbacks = [];
        // 失败存放法数组
        this.onRejectedCallbacks = [];
        let resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            // 一旦resolve执行,调用成功数组的函数
            this.onResolvedCallbacks.forEach(fn=>fn());
          }
        };
        let reject = reason => {
          if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            // 一旦reject执行,调用失败数组的函数
            this.onRejectedCallbacks.forEach(fn=>fn());
          }
        };
        try{
          executor(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
      then(onFulfilled,onRejected) {
        if (this.state === 'fulfilled') {
          onFulfilled(this.value);
        };
        if (this.state === 'rejected') {
          onRejected(this.reason);
        };
        // 当状态state为pending时
        if (this.state === 'pending') {
          // onFulfilled传入到成功数组
          this.onResolvedCallbacks.push(()=>{
            onFulfilled(this.value);
          })
          // onRejected传入到失败数组
          this.onRejectedCallbacks.push(()=>{
            onRejected(this.reason);
          })
        }
      }
    }

    第五步:链式调用

    new Promise().then().then()

    这就是链式调用,用来解决回调地狱

    1、为了达成链式,我们默认在第一个then里返回一个promise,叫promise2,将它传递下一个then中。

    2、我们需要在then中return一个参数,这个就叫x,x如果是promise,则取它的结果,作为promise2成功的结果。如果是普通值,直接作为promise2成功的结果,判断x的函数叫resolvePromise,带四个参数(promise2,x,resolve,reject)

    class Promise{
      constructor(executor){
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        let resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            this.onResolvedCallbacks.forEach(fn=>fn());
          }
        };
        let reject = reason => {
          if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn=>fn());
          }
        };
        try{
          executor(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
      then(onFulfilled,onRejected) {
        // 声明返回的promise2
        let promise2 = new Promise((resolve, reject)=>{
          if (this.state === 'fulfilled') {
            let x = onFulfilled(this.value);
            // resolvePromise函数,处理自己return的promise和默认的promise2的关系
            resolvePromise(promise2, x, resolve, reject);
          };
          if (this.state === 'rejected') {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          };
          if (this.state === 'pending') {
            this.onResolvedCallbacks.push(()=>{
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            })
            this.onRejectedCallbacks.push(()=>{
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            })
          }
        });
        // 返回promise,完成链式
        return promise2;
      }
    }

    第六步:实现resolvePromise函数

    function resolvePromise(promise2, x, resolve, reject){
      // 循环引用报错
      if(x === promise2){
        // reject报错(检测到promise的链接循环
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
      // 防止多次调用
      let called;
      // x不是null 且x是对象或者函数
      if (x != null && (typeof x === 'object' || typeof x === 'function')) {
        try {
          // A+规定,声明then = x的then方法
          let then = x.then;
          // 如果then是函数,就默认是promise了
          if (typeof then === 'function') { 
            // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
            then.call(x, y => {
              // 成功和失败只能调用一个
              if (called) return;
              called = true;
              // resolve的结果依旧是promise 那就继续解析
              resolvePromise(promise2, y, resolve, reject);
            }, err => {
              // 成功和失败只能调用一个
              if (called) return;
              called = true;
              reject(err);// 失败了就失败了
            })
          } else {
            resolve(x); // 直接成功即可
          }
        } catch (e) {
          // 也属于失败
          if (called) return;
          called = true;
          // 取then出错了那就不要在继续执行了
          reject(e); 
        }
      } else {
        resolve(x);
      }
    }

    第七步:解决一些问题

    1、onFulfilled或onRejected不能同步被调用,必须异步调用。我们就用setTimeout解决异步问题

    2、onFulfilled返回一个普通的值,成功时直接等于 value => value

    3、onRejected返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个then中的onFulfilled中,所以直接扔出一个错误 reason => throw err

    class Promise{
      constructor(executor){
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        let resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            this.onResolvedCallbacks.forEach(fn=>fn());
          }
        };
        let reject = reason => {
          if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn=>fn());
          }
        };
        try{
          executor(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
      then(onFulfilled,onRejected) {
        // onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        // onRejected如果不是函数,就忽略onRejected,直接扔出错误
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        let promise2 = new Promise((resolve, reject) => {
          if (this.state === 'fulfilled') {
            // 异步
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e);
              }
            }, 0);
          };
          if (this.state === 'rejected') {
            // 异步
            setTimeout(() => {
              // 如果报错
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e);
              }
            }, 0);
          };
          if (this.state === 'pending') {
            this.onResolvedCallbacks.push(() => {
              // 异步
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e);
                }
              }, 0);
            });
            this.onRejectedCallbacks.push(() => {
              // 异步
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e);
                }
              }, 0)
            });
          };
        });
        // 返回promise,完成链式
        return promise2;
      }
    }

    祝贺:一个promise就在自己笔下诞生啦~~

    参考资料:

    https://github.com/xieranmaya/blog/issues/3

  • 相关阅读:
    SpringData JPA 使用原生 SQL
    解决:CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
    Java 正则表达式 简单用法
    Java文件I/O简单介绍
    理清 UT、UTC、GMT和CST
    【LeetCode】面试题62. 圆圈中最后剩下的数字
    【阅读笔记】Java核心技术卷一 #6.Chapter8
    【阅读笔记】Java核心技术卷一 #5.Chapter7
    【阅读笔记】Java核心技术卷一 #4.Chapter6
    SQL面试题
  • 原文地址:https://www.cnblogs.com/Joe-and-Joan/p/11206579.html
Copyright © 2011-2022 走看看