手写一个 promise

66 阅读3分钟

Promise

手写一个 promise

  • testP = new testPromise()

1. 实例化的 p

<script type="module">
const testP = new testPromise((resolve, reject) => {
    // resolve('我成功了!');
    reject('我失败了!');
  });
console.log(testP, 'testP');
</script>

p的实例.png

class testPromise {
  constructor(handle){
    this['[[PromiseState]]'] = 'pending';   // promise 执行的状态
    this['[[PromiseResult]]'] = undefined;  // 存放的值 

    handle(this.resolve.bind(this), this.reject.bind(this))
  };
  resolve(value) {
    this.status = 'fulfilled';
    this.result = value;
  };
  reject(err) {
    this.status = 'rejected';
    this.result = err;
  };
};

2. P.then(onResolved, onRejected)

  • 回调函数 异步执行 onResolved 获取 Promise 中 resolve('我成功了!') 传出来的值,onRejected 获取 Promise 中 reject('我失败了!') 传出来的值
<script type="module">
const testP = new testPromise((resolve, reject) => {
    // resolve('我成功了!');
    reject('我失败了!');
  });
testP.then((res) => {
   console.log(res, 'testP1');
 }, err => {
   console.log(err, 'err1')
 });
    
testP.then((res) => {
    console.log(res, 'testP2');
 }, err => {
    console.log(err, 'err2')
 });
 
// then 的链式调用
  testP.then((res) => {
    // console.log(res, 'testP1');
    let a = `${res} + testP1`
    return a
  }, err => {
    console.log(err, 'err1')
    return '我错了'
  }).then(res => {
    console.log(res, 'res2')
  });
</script>
class testPromise {
  constructor(handle){
    this['[[PromiseState]]'] = 'pending';   // promise 执行的状态
    this['[[PromiseResult]]'] = undefined;  // 存放的值 
    
    // 存储函数
    this.resolveQueue = [];
    this.rejectQueue = [];

    handle(this.resolve.bind(this), this.reject.bind(this))
  };
  resolve(value) {
    this['[[PromiseState]]'] = 'fulfilled';
    this['[[PromiseResult]]'] = value;

    const run = () => {
      let cb;
      while(cb = this.resolveQueue.shift()){
        cb && cb(value);
      }
    };
    setTimeout(()=> {
      run();
    },1000)
  };
  reject(err) {
    this['[[PromiseState]]'] = 'rejected';
    this['[[PromiseResult]]'] = err;

    const run = () => {
      let cb;
      while(cb = this.rejectQueue.shift()){
        cb && cb(err);
      }
    };
    setTimeout(()=> {
      run();
    },1000)
  };
  then(onResolved, onRejected) {
    this.resolveQueue.push(onResolved);
    this.rejectQueue.push(onRejected);
  }
};
  • resolveQueuerejectQueue 是存放执行函数的,之所以是数组 是因为可以多次调用,如果不用数组的话,就会执行最后一个,其中存放的函数必须要在 resolvereject 执行完毕之后在执行,从而获取 valueerr 的值,此时在 run 加一个定时器就是为了满足这个需求,但是这样会出现一个新的问题,promise.then() 中的回调函数是 异步微任务,其执行的顺序应该在定时器之前,对于这个问题目前有两个结局方案:
  resolve(value) {
    this['[[PromiseState]]'] = 'fulfilled';
    this['[[PromiseResult]]'] = value;

    const run = () => {
      let cb;
      while(cb = this.resolveQueue.shift()){
        cb && cb(value);
      }
    };
    // setTimeout(()=> {
    //   run();
    // },1000)
    const observer = new MutationObserver(run);
    observer.observe(document.body, { attributes: true });
    document.body.setAttribute('key', 'value')
  };
  reject(err) {
    this['[[PromiseState]]'] = 'rejected';
    this['[[PromiseResult]]'] = err;

    const run = () => {
      let cb;
      while(cb = this.rejectQueue.shift()){
        cb && cb(err);
      }
    };
    // setTimeout(()=> {
    //   run();
    // },1000)
    // queueMicrotask 是用来执行微任务的,绑定在 window 上
    queueMicrotask(
      run
    );
  };
  • 第一种:监听属性的变化 是微任务,第二种 queueMicrotask 是用来执行微任务的

  • promise.then() 的链式调用

  then(onResolved, onRejected) {
    return new testPromise((resolve, reject) => {
      // 要判断 return 的是不是 Promise 对象
      let resolveFn = (value) => {
        let result = onResolved && onResolved(value);
        if(result instanceof testPromise) {
          // 执行 result.then 是递归  其中的 resolve 方法 是为了获取最后的值
          result.then(
            resolve
          )
        } else {
          resolve(result);
        }
      }
      this.resolveQueue.push(resolveFn);

      let rejectFn = (err) => {
        onRejected && onRejected(err);
        reject()
      }
      this.rejectQueue.push(rejectFn);
    })
  }
  • promise.then的链式调用,promise.then() 返回的是 Promise 对象
  then(onResolved, onRejected) {
    return new testPromise((resolve, reject) => {
      // 要判断 return 的是不是 Promise 对象
      let resolveFn = (value) => {
        let result = onResolved && onResolved(value);
        if(result instanceof testPromise) {

          // 执行 result 中的 resolve 方法
          result.then(
            resolve
          )
        } else {
          resolve(result);
        }
      }
      this.resolveQueue.push(resolveFn);

      let rejectFn = (err) => {
        onRejected && onRejected(err);
        reject()
      }
      this.rejectQueue.push(rejectFn);
    })
  };

3. Promise.resolve() 和 Promise.reject( )

  • 将 Promise 转化成当前所需的 Promise 对象
 <script type="module">
 	const pResolve = testPromise.resolve('我成功了哈');
  	console.log(pResolve, 'pResolve');
    const pReject = testPromise.reject('我失败了哈');
  	console.log(pReject, 'pReject')
 </script>
  // 类中的静态方法没办法调用属性和方法
  static resolve(value) {
    return new testPromise(resolve => {
      resolve(value);
    });
  };
  static reject(err) {
    return new testPromise((resolve, reject) => {
      reject(err);
    });
  };

4. p.catch()

  • 捕获 Promise 对象中的 reject传的值,如果你只要获取 reject 传的值,不需要获取 resolve 传的值,就不需要使用 then方法
<script type="module">
  testP.catch(err => {
    console.log(err, 'catch 捕获错误');
  });
 </script>
  catch(onRejected) {
    return this.then(undefined, onRejected);
  };

5. Promise.race()

  • 函数返回一个 Promise 对象,传的是一个数组
  • race 是竞赛的意思,就是数组中的 promise 对象中最先执行完的promise对象,并返回那个promise结果的结果
 <script type="module">
   const MyP1 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP1');
        // reject('MyErr');
      }, 2000);
    });
    const MyP2 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP2');
      }, 1000);
    });
    testPromise.race([MyP1, MyP2]).then(res => {
      console.log(res, 'res111');
    }, err => {
      console.log(err, 'err222');
    });
 </script> 
  • 上述实例中:最先执行完的是 MyP2,打印的结果是MyP2 err111
static race(lists) {
    let status = false
    return new testPromise((resolve, reject) => {
        lists.forEach(item => {
            item.then(res => {
                if(!status) {
                    resolve(res);
                    status = true;
                }
            }, err => {
                if(!status) {
                    reject(err);
                    status = true;
                }
            })
        })
    })
};

6. Promise.allSettled()

  • 函数返回一个 Promise 对象,传的是一个数组

  • 获取的结果如下: allSettled.png


   <script type="module">
   const MyP1 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP1');
        // reject('MyErr');
      }, 2000);
    });
    const MyP2 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP2');
      }, 1000);
    });
    testPromise.allSettled([MyP1, MyP2]).then(res => {
      console.log(res, '2222222');
    });
 </script> 
  static allSettled(lists) {
    // let resArr = [];
    let resArr = new Array(lists.length);
    let num = 0
    return new testPromise((resolve, reject) => {
      lists.forEach((item, key) => {
        const obj = {};
        item.then(res => {
          obj['status'] = 'fulfilled';
          obj['value'] = res;
          resArr[key] = obj; 
          num ++ 
          if(num >= lists.length) {
            console.log(resArr, 'resArr1');
            resolve(resArr)
          }
        }, err => {
          obj['status'] = 'rejected';
          obj['reson'] = err;
          resArr[key] = obj;
          num ++ 
          if(num >= lists.length) {
            // 最后都是 resolve 出结果
            resolve(resArr)
          }
        })
      })
    })
  }

7. Promise.all()

  • 可以同时调用多个异步请求,res 返回的是数组,如何请求中有一个报错,则 返回的是 err,简而言之,就是 promise.all()中发请求的数组有一个报错,则都不会返回结果,只会返回一个 err 的错误
   <script type="module">
   const MyP1 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP1');
        // reject('MyErr');
      }, 2000);
    });
    const MyP2 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP2');
      }, 1000);
    });
    const MyP3 = new testPromise((resolve,reject) => {
      setTimeout(()=> {
        resolve('MyP3');
        // reject('MyP3');
      }, 2000);
    });
    MyPromise.all([MyP1, MyP2, MyP3]).then(res =>{
      console.log(res, 'MyPromise all');
    }, err => {
      console.log(err, 'err');
    });
 </script> 
  static all(lists) {
    return new testPromise((resolve, reject) => {
      const resArr = new Array(lists.length);
      let num = 0;
      lists.forEach((item, key) => {
        item.then(res => {
          resArr[key] = res;
          num++

          if(num >= lists.length) {
            resolve(resArr);
          }
        }, err => {
          reject(err);
        });
      })
    })
  };

8. Promise.finally()

  • finally 不接受任何参数
  • finally 在 catch 或 then 执行完毕之后再执行的,如果请求发送成功和失败都要执行事件的话,可以写在finally中,避免重复书写
<script type="module">
    testP.finally(() => {
      console.log('myP 我被调用了');
    });
 </script> 
  finally(cb) {
    this.then(cb, cb);
  }