JavaScript--手写Promise机制

68 阅读1分钟

手写Promise机制前,我们先了解下来源。这个来源主要从promise a+ 这么一个规范而得的。我们从面试的角度上看,如果写这么一个上万行代码的规范,其实是不现实的。1、时间上面试一共1个多小时,不可能都放在这个方面,2、平时不会去手写,没必要。因为有现成的库和源码。那么接下来我们,来实现一个横扫面试的Promise机制。

class MyPromise {
  state = "pending"; // pending fulfilled rejected
  value = undefined;
  reason = undefined;

  resolveCallbacks = [];
  rejectCallbacks = [];

  constructor(fn) {
    const resolveHandler = (value) => {
      setTimeout(() => { //为了实现异步调用
        if (this.state === "pending") {
          this.state = "fulfilled";
          this.value = value;
          this.resolveCallbacks.forEach((fn) => fn(value));
        }
      });
    };

    const rejectHandler = (reason) => {
      setTimeout(() => { //为了实现异步调用
        if (this.state === "pending") {
          this.state = "rejected";
          this.reason = reason;
          this.rejectCallbacks.forEach((fn) => fn(reason));
        }
      });
    };

    try {
      fn(resolveHandler, rejectHandler);
    } catch (err) {
      rejectHandler(err);
    }
  }

  then(fn1, fn2) {
    fn1 = typeof fn1 === "function" ? fn1 : (v) => v;
    fn2 = typeof fn2 === "function" ? fn2 : (e) => e;

    if (this.state === "pending") {
      const p1 = new MyPromise((resolve, reject) => {
        this.resolveCallbacks.push(() => {
          try {
            const newValue = fn1(this.value);
            resolve(newValue);
          } catch (err) {
            reject(err);
          }
        });

        this.rejectHandler.push(() => {
          try {
            const newReason = fn2(this.reason);
            reject(newReason);
          } catch (err) {
            reject(err);
          }
        });
      });

      return p1;
    }

    if (this.state === "fulfilled") {
      const p1 = new MyPromise((resolve, reject) => {
        try {
          const newValue = fn1(this.value);
          resolve(newValue);
        } catch (err) {
          reject(err);
        }
      });
      return p1;
    }

    if (this.state === "rejected") {
      const p1 = new MyPromise((resolve, reject) => {
        try {
          const newReason = fn2(this.reason);
          reject(newReason);
        } catch (err) {
          reject(err);
        }
      });
      return p1;
    }
  }
  //就是then函数调用,一个语法糖
  catch(fn) {
    return this.then(null, fn);
  }
}

MyPromise.resolve = function (value) {
  return new MyPromise((resolve, reject) => resolve(value));
};

MyPromise.reject = function (reason) {
  return new MyPromise((resolve, reject) => reject(reason));
};

MyPromise.all = function (promiseList = []) {
  const p1 = new MyPromise((resolve, reject) => {
    const reasults = [];
    const length = promiseList.length;
    let resolveCount = 0;

    promiseList.forEach((p) => {
      p.then((data) => {
        reasults.push(data);
        resolveCount++;
        if (resolveCount === length - 1) {
          resolve(reasults);
        }
      }).catch((err) => {
        reject(err);
      });
    });
  });
  return p1;
};

MyPromise.race = function (promiseList = []) {
  const p1 = new MyPromise((resolve, reject) => {
    let isResolved = false; //标记
    promiseList.forEach((p) => {
      p.then((data) => {
        if (!isResolved) {
          resolve(data);
          isResolved = true;
        }
      }).catch((err) => {
        reject(err);
      });
    });
  });

  return p1;
};

下面这个是如何验证,我们手写Promise机制的函数调用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="./MyPromise.js"></script>
    <script>
        //初始化MyPromise类
        const p1 = new MyPromise((resolve, reject) => {
            //调用resolve函数
            resolve(100)
            //调用reject函数
            reject('错误信息...')
            //执行异步任务,验证函数回调
            setTimeout(()=> {
                console.log('1111')
            }, 1000)
        })

        //链式调用,并且执行then函数
        const p12 = p1.then((data) => {
            console.log('data', data)
            return data + 1
        })

        //链式调用,多次执行then函数
        const p13 = p12.then((data) => {
            console.log('data1', data)
            return data + 1
        })

        //链式调用,执行catch函数
        const p14 = p13.catch((err) =>  console.error('错误信息。。。'))

        //静态方法执行resolve函数
        const p2 = MyPromise.resolve(100)
        const p3 = MyPromise.resolve(200)
        //静态方法执行reject函数
        const p4 = MyPromise.reject('错误信息...')

        //传入 promise 数组,等待所有的都 fulfilled 之后,返回新 promise ,包含前面所有的结果
        const p5 = MyPromise.all([p1, p2, p3])
        p5.then((data)=> {console.log('all result', data)})

        // 传入 promise 数组,只要有一个 fulfilled 即可返回
        const p6 = MyPromise.race([p1,p2,p3])
        p6.then((data) => {console.log('race result', data)})
    </script>
    
</body>

</html>