JavaScript异步编程规范->实现一个简易版本的 Promise_js实现一个promise

+ - 2.1.1.初始化状态及返回值
	- 2.1.2.实现resolve/reject
	- 2.1.3.状态不可逆
	- 2.1.4.处理throw
+ 2.2.then
+ - 2.2.1.实现then
	- 2.2.2.通过队列实现setTimeout
	- 2.2.3.链式调用
	- 2.2.4.执行顺序
+ 2.3.其他方法
+ - 2.3.1.all
	- 2.3.2.race
	- 2.3.3.allsetled
	- 2.3.4.any
  • 3.最终代码

1.Promise基本使用

  • Promise 是一个构造函数
  • 通过 new 创建
  • 接收一个拥有 resolvereject 两个参数的 callback
let p1 = new Promise((resolve, reject) => {});
console.log("p1", p1);

let p2 = new Promise((resolve, reject) => {
  resolve("success");
  reject("error");
});
console.log("p2", p2);

let p3 = new Promise((resolve, reject) => {
  reject("error");
  resolve("success");
});
console.log("p3", p3);

let p4 = new Promise((resolve, reject) => {
  throw "报错啦~";
});
console.log("p4", p4);


这里说明了 Promise 的五个特点:

  1. 初始化的时候,Promise状态为pending
  2. 执行了resolvePromise状态会变成fulfilled
  3. 执行了rejectPromise状态会变成rejected
  4. Promise状态不可逆,第一次成功就永久为fulfilled,第一次失败就永远状态为rejected
  5. Promise中有throw的话,就相当于执行了reject

在这里插入图片描述

2.实现一个Promise

2.1.resolve/reject

2.1.1.初始化状态及返回值
  • 初始状态为 pending
class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
  }
}


在这里插入图片描述

2.1.2.实现resolve/reject
  • new 的时候接收 resolvereject,并修改状态
class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    exector(this.resolve, this.reject);
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
  }
  resolve(value) {
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
  }
  reject(reason) {
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将传递进来的错误抛出
    this.PromiseResult = reason;
  }
}


测试:

let test = new myPromise((resolve, reject) => {
  resolve("成功啦~");
  reject("失败啦~");
});
console.log(test);

此时发现报错了,经过排查原因发现是 this 指向问题,当 new MyPromise 创建实例对象后,此时 test 上还没有绑定 resolve和reject方法;
在这里插入图片描述

增加一个 initBind 方法,用于初始化时将 this 绑定到实例对象上:

class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    exector(this.resolve, this.reject);
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
  }
  reject(reason) {
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将传递进来的错误抛出
    this.PromiseResult = reason;
  }
}

let test = new myPromise((resolve, reject) => {
  resolve("成功啦~");
  reject("失败啦~");
});
console.log(test);


测试:

let test = new myPromise((resolve, reject) => {
  resolve("成功啦~");
  reject("失败啦~");
});

此时已经可以正常执行了:

在这里插入图片描述

2.1.3.状态不可逆

我们知道原生的 Promise 状态是不可逆的,只能改变一次,预期只执行 resolve, 但是这里也执行了 reject,改造如下:

class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    exector(this.resolve, this.reject);
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
  }
  reject(reason) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将传递进来的错误抛出
    this.PromiseResult = reason;
  }
}

测试:

let test1 = new myPromise((resolve, reject) => {
  resolve("成功啦test1~");
  reject("失败啦test1~");
});
console.log(test1);

let test2 = new myPromise((resolve, reject) => {
  reject("失败啦test2~");
  resolve("成功啦test2~");
});
console.log(test2);

此时状态已不可逆:

在这里插入图片描述

2.1.4.处理throw

此时如果直接抛出错误,会怎么样呢?

let test3 = new myPromise((resolve, reject) => {
  throw "报错啦test3~";
});
console.log(test3);

由原生 Promise 可以知道,如果直接抛出错误,那么状态和 reject 执行时一样,都是 rejected ,此时不满足预期的功能:

在这里插入图片描述
继续改造,增加 try catch 来处理异常:

class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    try {
      // 正常执行的话,执行 exector
      exector(this.resolve, this.reject);
    } catch(err) {
      // 捕获到异常,则执行一次 reject
      this.reject(err);
    }
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
  }
  reject(reason) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将残敌进来的错误抛出
    this.PromiseResult = reason;
  }
}

测试:

let test3 = new myPromise((resolve, reject) => {
  throw "报错啦test3~";
});
console.log(test3);

此时已经满足了预期的功能:

在这里插入图片描述

2.2.then

平时业务中then的使用一般如下:

// 马上输出 -> "成功了"
const p1 = new Promise((resolve, reject) => {
  resolve("成功了"); // 成功的话,执行 then 中的成功回调
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
);

// 1秒后输出 -> "失败了"
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("失败了"); // 失败的话执行 then 中的失败回调
  }, 1000);
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
);

// 链式调用 -> 输出 200
const p3 = new Promise((resolve, reject) => {
  resolve(100); // 成功的话执行 then 中成功的回调
})
  .then(
    (res) => 2 \* res,
    (err) => console.log(err)
  )
  .then(
    (res) => console.log(res),
    (err) => console.log(err)
  );

总结 then 的使用规则:

  1. then 接收两个参数,一个是成功回调,一个是失败回调;
  2. 状态为 fulfilled 时执行成功回调,状态为 rejected 时执行失败回调;
  3. resolvereject 可以在定时器中,并且定时器时间结束后依次执行
  4. then 可以链式调用,上一次 then 的返回值传递给下一个 then
2.2.1.实现then

根据上面总结的规则,声明一个 then 函数:

class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    try {
      // 正常执行的话,执行 exector
      exector(this.resolve, this.reject);
    } catch(err) {
      // 捕获到异常,则执行一次 reject
      this.reject(err);
    }
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
  }
  reject(reason) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将残敌进来的错误抛出
    this.PromiseResult = reason;
  }
  then(onFulfilled, onRejected) {
    // then 函数接收两个callback,一个是成功回调,一个是失败回调
    // 参数兜底处理,确保返回的都是回调函数
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected = typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    // 如果成功,则执行成功回调
    // 如果失败,则执行失败回调
    if (this.PromiseState === "fulfilled") {
      onFulfilled(this.PromiseResult);
    } else if (this.PromiseState === "rejected") {
      onRejected(this.PromiseResult);
    }
  }
}


测试:

let test1 = new myPromise((resolve, reject) => {
  resolve(10);
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
);

then 的基本功能已实现:

在这里插入图片描述

2.2.2.通过队列实现setTimeout

下面的代码如何按预期的 1s 之后再执行呢?

// 1秒后输出 ”fail“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('fail')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

  1. 我们不能保证 1s 之后才执行 then ,但是换个思路我们可以保证 then 中的回调,1s之后再执行;
  2. 在这 1s 中,可以先把 then 中的回调报错起来,等 resolve 或者 reject 执行之后,再去执行保存的回调函数。
  3. 只要执行 resolve 或者 reject 那么状态就会发生变化,只需要在状态为 pending 时使用一个数组将回调保存起来即可:
class myPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    try {
      // 正常执行的话,执行 exector
      exector(this.resolve, this.reject);
    } catch(err) {
      // 捕获到异常,则执行一次 reject
      this.reject(err);
    }
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
    this.onFulfilledCallbacks = []; // 保存成功的回调
    this.onRejectedCallbacks = []; // 保存失败的回调
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
    // 执行成功的回调
    while (this.onFulfilledCallbacks.length) {
      // 每次从队列中取出一个来执行
      this.onFulfilledCallbacks.shift()(this.PromiseResult);
    }
  }
  reject(reason) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将传递进来的错误抛出
    this.PromiseResult = reason;
    // 执行成功的回调
    while (this.onRejectedCallbacks.length) {
      // 每次从队列中取出一个来执行
      this.onRejectedCallbacks.shift()(this.PromiseResult);
    }
  }
  then(onFulfilled, onRejected) {
    // then 函数接收两个callback,一个是成功回调,一个是失败回调
    // 参数兜底处理,确保返回的都是回调函数
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    // 如果成功,则执行成功回调
    // 如果失败,则执行失败回调
    if (this.PromiseState === "fulfilled") {
      onFulfilled(this.PromiseResult);
    } else if (this.PromiseState === "rejected") {
      onRejected(this.PromiseResult);
    } else if (this.PromiseState === "pending") {
      // 将成功回调放入队列
      this.onFulfilledCallbacks.push(onFulfilled);
      // 将失败回调放入队列
      this.onRejectedCallbacks.push(onRejected);
    }
  }
}

测试:

let test1 = new myPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功回调test1");
  }, 1000);
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
);
let test2 = new myPromise((resolve, reject) => {
  setTimeout(() => {
    reject("失败回调test2");
  }, 2000);
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
);

1s 之后执行成功回调,2s 之后执行失败回调,此时是满足预期的:

在这里插入图片描述

2.2.3.链式调用

此时还有一个问题,原生 Promise 是支持链式调用的,并且上一次 then 的值会传递给下一次 then,如下面这个例子:

// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
  resolve(100)
}).then(res => 2 \* res, err => console.log(err))
  .then(res => console.log(res), err => console.log(err))

// 链式调用 输出300
const p4 = new Promise((resolve, reject) => {
  resolve(100)
}).then(res => new Promise((resolve, reject) => resolve(3 \* res)), err => console.log(err))
  .then(res => console.log(res), err => console.log(err))

MyPromise 目前还不支持。
为什么 Promise 能支持链式调用呢?
因为在 then 方法执行完成之后,返回值被包装成了一个 Promise

  1. then 方法本身会返回一个新的 Promise 对象;
  2. 如果返回值是 promise 对象,返回值为成功,新 promise 就是成功;
  3. 如果返回值是 promise 对象,返回值为失败,新 promise 就是失败;
  4. 如果返回值非 promise 对象,新 promise 对象就是成功,值为此返回值;

改造 MyPromise

class MyPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    try {
      // 正常执行的话,执行 exector
      exector(this.resolve, this.reject);
    } catch (err) {
      // 补货到异常,则执行一次 reject
      this.reject(err);
    }
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
    this.onFulfilledCallbacks = []; // 保存成功的回调
    this.onRejectedCallbacks = []; // 保存失败的回调
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 fulfilled
    this.PromiseState = "fulfilled";
    // 将传递进来的参数赋值
    this.PromiseResult = value;
    // 执行成功的回调
    while (this.onFulfilledCallbacks.length) {
      // 每次从队列中取出一个来执行
      this.onFulfilledCallbacks.shift()(this.PromiseResult);
    }
  }
  reject(reason) {
    // 只要状态已经改变,就不允许继续修改状态
    if (this.PromiseState !== "pending") {
      return;
    }
    // 此时状态改为 rejected
    this.PromiseState = "rejected";
    // 将传递进来的错误抛出
    this.PromiseResult = reason;
    // 执行成功的回调
    while (this.onRejectedCallbacks.length) {
      // 每次从队列中取出一个来执行
      this.onRejectedCallbacks.shift()(this.PromiseResult);
    }
  }
  then(onFulfilled, onRejected) {
    // then 函数接收两个callback,一个是成功回调,一个是失败回调
    // 参数兜底处理,确保返回的都是回调函数
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };
    var promiseThen = new MyPromise((resolve, reject) => {
      const handlePromise = (fn) => {
        try {
        let f = fn(this.PromiseResult);
          if (f === promiseThen) {
            // 不能返回自身
            throw new Error("不能返回自身。。。");
          }
          if (f instanceof MyPromise) {
            // 如果是 Promise 则执行对应的回调
            f.then(resolve, reject);
          } else {
            // 如果不是 Promise 则直接成功
            resolve(f);
          }
        } catch (error) {
          // 处理报错, 预防一些边界情况
          reject(error);
          throw new Error(error);
        }
      };
      // 如果成功,则执行成功回调
      // 如果失败,则执行失败回调
      if (this.PromiseState === "fulfilled") {
        // onFulfilled(this.PromiseResult);
        handlePromise(onFulfilled);
      } else if (this.PromiseState === "rejected") {
        // onRejected(this.PromiseResult);
        handlePromise(onRejected);
      } else if (this.PromiseState === "pending") {
        // 将成功回调放入队列
        this.onFulfilledCallbacks.push(handlePromise(onFulfilled));
        // 将失败回调放入队列
        this.onRejectedCallbacks.push(handlePromise(onRejected));
      }
    });

    // 返回包装的 Promise
    return promiseThen;
  }
}

测试:

const test1 = new MyPromise((resolve, reject) => {
  resolve(100);
})
  .then(
    (res) => 2 \* res,
    (err) => 3 \* err
  )
  .then(
    (res) => console.log("success", res),
    (err) => console.log("fail", err)
  );

const test2 = new MyPromise((resolve, reject) => {
  resolve(100);
})
  .then(
    (res) => new MyPromise((resolve, reject) => reject(2 \* res)),
    (err) => new Promise((resolve, reject) => resolve(3 \* err))
  )
  .then(
    (res) => console.log("success", res),
    (err) => console.log("fail", err)
  );

在这里插入图片描述

2.2.4.执行顺序

then 是微任务,因此执行会晚于全局上下文,例如:

const p = new Promise((resolve, reject) => {
    resolve(1)
}).then(res => console.log(res), err => console.log(err))

console.log(2)

// 输出顺序是 2 1

在我们的 MyPromise 中暂未实现该功能,此处可以通过 setTimeout 宏任务来将 then 异步执行:

class MyPromise {
  constructor(exector) {
    // 初始化状态及初始值
    this.initValue();
    // 初始化的时候改变 this 指向,将 this 指向实例对象
    this.initBind();
    // 执行器,当 new MyPromise()时,这个callback要接受 resolve 和 reject 函数
    try {
      // 正常执行的话,执行 exector
      exector(this.resolve, this.reject);
    } catch (err) {
      // 补货到异常,则执行一次 reject
      this.reject(err);
    }
  }
  initValue() {
    this.PromiseState = "pending"; // Promise 状态
    this.PromiseResult = undefined; // Promise 返回值
    this.onFulfilledCallbacks = []; // 保存成功的回调
    this.onRejectedCallbacks = []; // 保存失败的回调
  }
  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }
  resolve(value) {


### 最后

我可以将最近整理的前端面试题分享出来,其中包含**HTML、CSS、JavaScript、服务端与网络、Vue、浏览器、数据结构与算法**等等,还在持续整理更新中,希望大家都能找到心仪的工作。


**篇幅有限,仅展示部分截图:**

![](https://img-blog.csdnimg.cn/img_convert/ff6b8e636a356a01389cd2de0211d347.png)

![](https://img-blog.csdnimg.cn/img_convert/b24f32dd81ead796fa80c27c763d262c.png)

![](https://img-blog.csdnimg.cn/img_convert/c6265dc2681708533916a8d7910506b3.png)
  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值