Skip to content

手写代码

手写 Promise

1. 初始结构

js
class MyPromise {
  static PENDING = "等待";
  static FULFILLED = "成功";
  static REJECTED = "失败";

  constructor(func) {
    this.status = MyPromise.PENDING;
    this.result = null;
    // 注意此处this指向, 需要绑定实例
    func(this.resolve.bind(this), this.reject.bind(this));
  }

  resolve(result) {
    this.status = MyPromise.FULFILLED;
    this.result = result;
  }
  reject(result) {
    this.status = MyPromise.REJECTED;
    this.result = result;
  }
}
// 调用
const p = new MyPromise((resolve, reject) => {
  resolve("success");
});

2. .then

then 接收两个执行函数, 分别状态成功和状态失败所执行的操作

js
class MyPromise {
  // ...
  then(onFULFILLED, onREJECTED) {
    if (this.status === MyPromise.FULFILLED) {
      onFULFILLED(this.result);
    }
    if (this.status === MyPromise.REJECTED) {
      onREJECTED(this.result);
    }
  }
}

const p = new MyPromise((resolve, reject) => {
  resolve("success");
});
p.then(
  (result) => {
    console.log(result);
  },
  (err) => {
    console.log(err);
  }
);

3. 处理异常

当抛出错误时, 要能捕获且输出

js
class MyPromise {
  // ...
  constructor(func) {
    this.status = MyPromise.PENDING;
    this.result = null;
    try {
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
  // ...
}
// 调用
const p = new MyPromise((resolve, reject) => {
  throw new Error("抛出错误");
});
p.then(
  (result) => {
    console.log(result);
  },
  (err) => {
    console.log(err);
  }
);
  • then 的传入参数不为函数时要忽略
js
class MyPromise {
  //...
  then(onFULFILLED, onREJECTED) {
    onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : () => {};
    onREJECTED = typeof onREJECTED === "function" ? onREJECTED : () => {};
    if (this.status === MyPromise.FULFILLED) {
      onFULFILLED(this.result);
    }
    if (this.status === MyPromise.REJECTED) {
      onREJECTED(this.result);
    }
  }
  //...
}
// 调用
const p = new MyPromise((resolve, reject) => {
  resolve("success");
});
p.then(undefined, (err) => {
  console.log(err);
});

4. 实现异步

在 then 内部给执行函数包上定时调用, 初步实现异步

js
class MyPromise {
  //...
  then(onFULFILLED, onREJECTED) {
    onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : () => {};
    onREJECTED = typeof onREJECTED === "function" ? onREJECTED : () => {};
    if (this.status === MyPromise.FULFILLED) {
      setTimeout(() => {
        onFULFILLED(this.result);
      });
    }
    if (this.status === MyPromise.REJECTED) {
      setTimeout(() => {
        onREJECTED(this.result);
      });
    }
  }
  //...
}

// 调用结果: 1 2 3 success
console.log(1);
const p = new MyPromise((resolve, reject) => {
  console.log(2);
  resolve("success");
});
p.then((result) => {
  console.log(result);
});
console.log(3);

5. 回调保存

当调用时使用 setTimeout, 需要将 then 中的事件回调保存起来, 等执行到 resolvereject 时处理

js
class MyPromise {
  //...
  constructor(func) {
    this.status = MyPromise.PENDING;
    this.result = null;
    this.resolveCallbacks = [];
    this.rejectCallbacks = [];
    try {
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(result) {
    setTimeout(() => {
      this.status = MyPromise.FULFILLED;
      this.result = result;
      this.resolveCallbacks.forEach((callback) => {
        callback(result);
      });
    });
  }
  reject(result) {
    setTimeout(() => {
      this.status = MyPromise.REJECTED;
      this.result = result;
      this.rejectCallbacks.forEach((callback) => {
        callback(result);
      });
    });
  }
  then(onFULFILLED, onREJECTED) {
    onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : () => {};
    onREJECTED = typeof onREJECTED === "function" ? onREJECTED : () => {};
    if (this.status === MyPromise.PENDING) {
      this.resolveCallbacks.push(onFULFILLED);
      this.rejectCallbacks.push(onREJECTED);
    }
    if (this.status === MyPromise.FULFILLED) {
      setTimeout(() => {
        onFULFILLED(this.result);
      });
    }
    if (this.status === MyPromise.REJECTED) {
      setTimeout(() => {
        onREJECTED(this.result);
      });
    }
  }
}

调用结果==>1 2 4 3 success

js
console.log(1);
const p = new MyPromise((resolve, reject) => {
  console.log(2);
  setTimeout(() => {
    resolve("success");
    console.log(3);
  });
});
p.then((result) => {
  console.log(result);
});
console.log(4);

6. 链式调用

实现 .then 链式调用, 以下是完整代码

js
class MyPromise {
  static PENDING = "等待";
  static FULFILLED = "成功";
  static REJECTED = "失败";

  constructor(func) {
    this.status = MyPromise.PENDING;
    this.result = null;
    this.resolveCallbacks = [];
    this.rejectCallbacks = [];
    try {
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(result) {
    setTimeout(() => {
      this.status = MyPromise.FULFILLED;
      this.result = result;
      this.resolveCallbacks.forEach((callback) => {
        callback(result);
      });
    });
  }
  reject(result) {
    setTimeout(() => {
      this.status = MyPromise.REJECTED;
      this.result = result;
      this.rejectCallbacks.forEach((callback) => {
        callback(result);
      });
    });
  }
  then(onFULFILLED, onREJECTED) {
    onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : () => {};
    onREJECTED = typeof onREJECTED === "function" ? onREJECTED : () => {};
    if (this.status === MyPromise.PENDING) {
      this.resolveCallbacks.push(onFULFILLED);
      this.rejectCallbacks.push(onREJECTED);
    }
    if (this.status === MyPromise.FULFILLED) {
      setTimeout(() => {
        onFULFILLED(this.result);
      });
    }
    if (this.status === MyPromise.REJECTED) {
      setTimeout(() => {
        onREJECTED(this.result);
      });
    }
    return this;
  }
}
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("success");
  });
});
p.then((result) => {
  console.log(result);
}).then(() => {
  console.log("链式调用");
});

深拷贝

js
function deepClone(obj = {}) {
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }
  let result = obj instanceof Array ? [] : {};
  for (const k in obj) {
    // 排除原型上的属性,如: Object.prototype.abc = '123' 中的abc
    if (Object.hasOwnProperty.call(obj, k)) {
      result[k] = deepClone(obj[k]);
    }
  }

  return result;
}