手写Promise

91 阅读7分钟

Promise 的简单用法。

  1. new Promise() 必须有回调函数。不然报错。
  2. 回调函数有两个参数分别是两个函数。一个是成功(resolve) 一个是失败。(reject)
  3. 这两个方法必须执行一个方法一般用于等待请求数据。
  4. 成功和失败我们都可以用then()来接收。then()有两个参数。都是函数。一个是接收成功的一个是接收失败的, 成功失败只能执行一个。
  5. 我们也可以用catch()放在then()后面调用。可以catch掉所有错误。
  6. then的第二个参数只能接收当前这个Promise的错误。 而catch()可以接收所有错误参数。
  7. then里面可以return Promise 也可以return 任意参数。都可以在下一个then()里面接收到。
const promise = new Promise(function(resolve, reject) {
  resolve('成功');
})

promise.then((res) => {
 console.log(res, 1111)
  return '2222'
}).then((e) => {
  console.log(e, 9999)
})
console.log(promise, 999);

Promise 静态方法

// 注定失败
Promise.reject('失败').catch((e) => {
console.log(1)
})
// 注定成功
Promise.resolve('成功').then((e) => {
  console.log(2)
})
// 所有成功才成功
Promise.all([Promise.reject('失败'), Promise.resolve('成功')]).then(() => {
  console.log(3)
}).catch((err) => {
   console.log(err, 4)
})
// 谁先返回成功就成功
Promise.race([Promise.resolve('1111'), Promise.reject('失败')]).then(() => {
  console.log(5)
}).catch((err) => {
   console.log(err, 6)
})

模拟Promise 源码

/**
 * 1. Promise 就是一个类, 在执行这个类的时候, 需要传递一个执行器进去 执行器会立即执行。
 * 2. Promise 中有三种状态 分别是成功 fulfilled 失败 rejected 等待 pending
 * 3. pending -> fulfilled
 * 4. pending -> rejected
 * 一旦状态确定就不可更改。
 * 5.resolve 和 reject 函数是用来更改状态的
 * resolve : fulfilled
 * reject : rejected
 * 调用then方法,有两个参数一个是成功之后的回调 ,一个是失败之后的回调。
 * 因为成功和失败只有一个会执行 。
 * */ 
 // 创建一个类。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJSCTED = 'rejected';
class MyPromise {
  // 构造器参数接收调用者传来的函数
  constructor (excutor) {
    // 函数立即执行
    excutor(resolve, reject);
  }
  status = PENDING;
  value =  undefined;
  reason = undefined;
  // 箭头函数让this一直指向这个对象。
  resolve = value => {
    if (this.status !== PENDING) return;
    status = FULFILLED;
    this.value = value;
  }
  reject = reason => {
    if (this.status !== PENDING) return;
    status = REJSCTED;
    this.reason = reason;
  }
  then (successCallback, failCallback) {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJSCTED) {
      failCallback(this.reason)
    }
  }
}

Promise 模拟源码————异步

当调用Promise 的时候调用执行器的时候,加一个setTimeout 因为上一个版本是同步执行的。 new MyPrimise()代码会立即执行。 而延时器并没有执行。 当执行栈所有东西执行完, MyPromisel里的状态还是pending的状态, 因为并没有传入改变状态的函数。 这个时候会执行到then方法里面。 但是我们只判断了成功和失败的处理方法。 这个时候我们需要加一个判断。 如果执行到then里面状态值是pending的时候。 我们用一个类的属性,将这个成功和失败的回调存起来。 这个时候会执行行延时器里面的东西。 这个时候调用成功的回调或者是失败的回调。 可以在失败或者成功的会回调里判断是否then里面存的函数。 如果有的话就执行。

const PENGING = 'pending';
const FULFILLED = 'fulilled';
const REJECTED = 'rejected'; 
class myPromise {
  constructor (excutor) {
    excutor(this.resolve, this.reject)
  }
  status = PENGING;
  value = undefined;
  reason = undefined;
  successCallback = undefined;
  failCallback = undefined;
  resolve = value => {
    //如果状态PENDING则继续执行。 否则阻止3执行
    if (this.status !== PENGING) return
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功之后的值。
    this.value = value;
    // 判断是否存在成功回调函数。
    this.successCallback && this.successCallback(this.value)
  }
  reject = reason => {
    //如果状态PENDING则继续执行。 否则阻止执行
    if (this.status !== PENGING) return
    // 将状态改为失败
    this.status = REJECTED;
    // 保存失败之后的原因。
    this.reason = reason;
    // 判断是否有失败回调函数。
    this.failCallback && this.failCallback(this.reason);
  }
  then (successCallback, failCallback) {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      failCallback(this.reason)
    } else {
      this.successCallback = successCallback;
      this.failCallback = failCallback;
    }
  }
}
module.exports = myPromise

多个then调用

思路将 successCallback = undefined; -> successCallback = []; failCallback = undefined; -> failCallback = []; 改成数组然后循环调用。

const PENGING = 'pending';
const FULFILLED = 'fulilled';
const REJECTED = 'rejected'; 
class myPromise {
  constructor (excutor) {
    excutor(this.resolve, this.reject)
  }
  status = PENGING;
  value = undefined;
  reason = undefined;
  successCallback = [];
  failCallback = [];
  resolve = value => {
    //如果状态PENDING则继续执行。 否则阻止3执行
    if (this.status !== PENGING) return
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功之后的值。
    this.value = value;
    // 判断是否存在成功回调函数。
    while (this.successCallback.length) this.successCallback.shift()(this.value)
  }
  reject = reason => {
    //如果状态PENDING则继续执行。 否则阻止执行
    if (this.status !== PENGING) return
    // 将状态改为失败
    this.status = REJECTED;
    // 保存失败之后的原因。
    this.reason = reason;
    // 判断是否有失败回调函数。
    while (this.failCallback.length) this.failCallback.shift()(this.reason)
  }
  then (successCallback, failCallback) {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      failCallback(this.reason)
    } else {
      this.successCallback.push(successCallback);
      this.failCallback.push(failCallback);
    }
  }
}
module.exports = myPromise

Promise 链式调用

分析: then方法链式调用。上一个then()方法返回值是 下一个then方法的接收值。也就是说返回是一个Promise 所以需要new Promise()

 then (successCallback, failCallback) {
    // new Promise 将上一次测返回值传到下一个接收。
    let Promise2 = new myPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        resolve(successCallback(this.value))
      } else if (this.status === REJECTED) {
        failCallback(this.reason)
      } else {
        this.successCallback.push(successCallback);
        this.failCallback.push(failCallback);
      }
    })
    
    return Promise2;
  }

判断then方法的返回值是什么 普通值还是Promise;

判断then方法的返回值是普通值还是Promise,如果是普通值就直接 返回。如果是promise就执行掉然后把结果返回。

then (successCallback, failCallback) {
    let Promise2 = new myPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        const x = successCallback(this.value)
        resolvePromise(x, resolve, reject)
      } else if (this.status === REJECTED) {
        failCallback(this.reason)
      } else {
        this.successCallback.push(successCallback);
        this.failCallback.push(failCallback);
      }
    })
    
    return Promise2;
  }
function resolvePromise (x, resolve, reject) {
  if (x instanceof myPromise) {
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}

判断自己返回自己的情况

then (successCallback, failCallback) {
    let Promise2 = new myPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          const x = successCallback(this.value)
          resolvePromise(Promise2, x, resolve, reject)
        }, 0)
      } else if (this.status === REJECTED) {
        failCallback(this.reason)
      } else {
        this.successCallback.push(successCallback);
        this.failCallback.push(failCallback);
      }
    })
    
    return Promise2;
  }
  function resolvePromise (Promise2, x, resolve, reject) {
  console.log(Promise2 === x, 8889999999)
  if (Promise2 === x) return reject('不能循环调用自己')
  if (x instanceof myPromise) {
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}

Promise 错误处理

  1. 将执行器try{}catch(){}捕获错误。
  2. then 方法成功的时候和失败的时候 还有异步处理的时候都需要
  3. 将错误捕获。 代码解析。
// Promise 的三个状态。
const PENGING = 'pending'; // 等待
const FULFILLED = 'fulilled'; // 成功
const REJECTED = 'rejected'; // 失败
// 创建Promise类。
class myPromise {
  // 构造器传过来一个执行函数。 
  constructor (excutor) {
    // 捕获执行器的错误。
    try{
      // 执行器执行 分别传出两个参数》函数 resolve reject
      excutor(this.resolve, this.reject)
    }
    catch (err) {
      // 报错执行错误函数。
      this.reject(err.message)
    }
  }
  // 记录Promise的状态
  status = PENGING;
  // 设置成功 默认值
  value = undefined;
  设置失败默认值
  reason = undefined;
  // 记录成功和失败函数数组。
  successCallback = [];
  failCallback = [];
  // 成功执行函数
  resolve = value => {
    //如果状态PENDING则继续执行。 否则阻止执行
    if (this.status !== PENGING) return
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功之后的值。
    this.value = value;
    // 判断是否存在成功回调函数。
    while (this.successCallback.length) this.successCallback.shift()()
  }
  // 失败执行函数。
  reject = reason => {
    //如果状态PENDING则继续执行。 否则阻止执行
    if (this.status !== PENGING) return
    // 将状态改为失败
    this.status = REJECTED;
    // 保存失败之后的原因。
    this.reason = reason;
    // 判断是否有失败回调函数。
    while (this.failCallback.length) this.failCallback.shift()()
  }
  // 当 执行器执行完成之后执行then方法获取结果。
  // 两个参数都是回调函数: successCallback failCallback
  then (successCallback, failCallback) {
    // then方法执行完都会返回一个新的Promise
    let Promise2 = new myPromise((resolve, reject) => {
      // 当上一个Promise执行完成的状态判断。成功 执行
      if (this.status === FULFILLED) {
        // 与同步之后执行为了获取到Promise2对象构造完成。
        // const x = successCallback(this.value)必须正在延迟器里调用的return 的对象才能接受到。
        setTimeout(() => {
          try {
            // 调用者返回的值
            const x = successCallback(this.value)
            // 解析Promise传过来的值。
            resolvePromise(Promise2, x, resolve, reject)
          }
          catch(err) {
            // catch 掉错误在下一个then方法 显示、
            reject(err.message)
          }
        }, 0)
      // 当上一个Promise执行完成的状态判断。失败 执行
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const x = failCallback(this.reason)
            resolvePromise(Promise2, x, resolve, reject)
          }
          catch(err) {
            reject(err.message)
          }
        }, 0)
      } else {
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              const x = successCallback(this.value)
              resolvePromise(Promise2, x, resolve, reject)
            }
            catch(err) {
              reject(err.message)
            }
          }, 0)
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              const x = failCallback(this.reason)
              resolvePromise(Promise2, x, resolve, reject)
            }
            catch(err) {
              reject(err.message)
            }
          }, 0)
        });
      }
    })
    
    return Promise2;
  }
}
/**
  * 解析Promise
  * Promise2 then方法返回的新的Promise
  * x 调用者返回的参数: 可以是普通参数也可以是别的
  * 如果参数是它 new Promise 本身的我们需要特殊处理下。
  */
function resolvePromise (Promise2, x, resolve, reject) {
  // 如果返回本身的话报错提示下
  if (Promise2 === x) return reject('不能循环调用自己')
  // 如果是调用者new Primise 我们 需要把这个Promise执行掉。然后返回结果。
  if (x instanceof myPromise) {
    x.then(resolve, reject);
  } else {
    // 如果是正常的值不是Promise的话我们直接返回。
    resolve(x);
  }
}
module.exports = myPromise

将then 方法参数变成可选参数

// 如果没有传参数的话就把上一个Promise执行的结果返回给下下一个参数。 
successCallback = successCallback ? successCallback : value => value;
    failCallback = failCallback ? failCallback : value => value;