简易版 promise 实现 + 步骤

102 阅读3分钟

简易版 promise 实现步骤

  1. 确定状态
  2. 实现 .then 调用和异步执行
  3. 实现 new Promise 内的异步逻辑
  4. 实现 .then 的链式调用

确定状态

promise 的状态是不可改变的,根据这一特性创建构造函数。 promise 函数接收一个 executor 函数,executor 函数执行完同步或异步操作后,调用它的参数 resolve 或 reject

class Promise2 {
  static PENDING = 'pending'
  static RESOLVED = 'resolved'
  static REJECTED = 'rejected'

  constructor(executor) {
    this.status = Promise2.PENDING
    this.value = ''
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }

  resolve(val) {
    if (this.status == Promise2.PENDING) {
      this.status = Promise2.RESOLVED
      this.value = val
    }
  }

  reject(val) {
    if (this.status == Promise2.PENDING) {
      this.status = Promise2.REJECTED
      this.value = val
    }
  }
}


const p1 = new Promise2((resolve, reject)=>{
  resolve(1)
})

console.log(p1); // { status: 'resolved', value: 1 }

实现 .then 调用和异步执行

then 接收两个参数,onResolved onRejected 分别为成功和失败的回调

class Promise2 {
  // ... 代码省略

  then(onResolved, onRejected) {
    // 根据标准,then 的参数需要是函数
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    if (typeof onRejected !== 'function') {
      onRejected = value => value
    }

    if(this.status == Promise2.RESOLVED) {
      try {
        onResolved(this.value)
      } catch (error) {
        onRejected(error)
      }
    }

    if(this.status == Promise2.REJECTED) {
      try {
        onRejected(this.value)
      } catch (error) {
        onRejected(error)
      }
    }
  }
}


const p1 = new Promise2((resolve, reject) => {
  resolve(1)
}).then(res => {
  console.log('res',res);
}, err => {
  console.log('err',err);
})

在看一个案例

const p1 = new Promise2((resolve, reject) => {
  resolve(1)
}).then(res => {
  console.log('res',res);
}, err => {
  console.log('err',err);
})


console.log('同步');
// 此时先打印 res 1, 后打印 同步

Promise 的机制是 then 回调函数必须异步执行。为什么?因为这样保障了代码执行顺序的一致性。 所以应该先打印 同步 后打印 res 1

if(this.status == Promise2.RESOLVED) {
  setTimeout(() => {
    try {
      onResolved(this.value)
    } catch (error) {
      onRejected(error)
    }
  });
  
}

if(this.status == Promise2.REJECTED) {
  setTimeout(() => {
    try {
      onRejected(this.value)
    } catch (error) {
      onRejected(error)
    }
  });
}

实现 new Promise 内的异步逻辑

const p1 = new Promise2((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 500);
})

console.log(p1); // { status: 'pending', value: '' }

通过上面测试案例可以,此时的 status 是 pending。所以我们在 .then 里在添加一个 status == 'pending' 的判断。
同时再添加一个 callbacks 属性,用于保存 .then(...) 里的函数。
那么什么时候执行 callbacks(.then(...)) 里的函数呢?
答案是我们把 callbacks 放在 resolve() 和 reject() 方法里。当 setTimeout 时间到了,执行 resolve(1) 的时候。

class Promise2 {
  static PENDING = 'pending'
  static RESOLVED = 'resolved'
  static REJECTED = 'rejected'

  constructor(executor) {
    this.status = Promise2.PENDING
    this.value = ''
    this.callbacks = [] // 新增
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }

  resolve(val) {
    if (this.status == Promise2.PENDING) {
      this.status = Promise2.RESOLVED
      this.value = val

      // 新增
      for (var i = 0; i < this.callbacks.length; i++) {
        this.callbacks[i].onResolved(this.value)
      }
    }
  }

  reject(val) {
    if (this.status == Promise2.PENDING) {
      this.status = Promise2.REJECTED
      this.value = val

      // 新增
      for (var i = 0; i < this.callbacks.length; i++) {
        this.callbacks[i].onRejected(this.value)
      }
    }
  }

  then(onResolved, onRejected) {
    // 根据标准,then 的参数需要是函数
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    if (typeof onRejected !== 'function') {
      onRejected = value => value
    }

    // 新增
    if (this.status == Promise2.PENDING) {
      this.callbacks.push({
        onResolved: (value) => {
          try {
            onResolved(this.value)
          } catch (error) {
            onRejected(error)
          }
        },
        onRejected: (value) => {
          try {
            onRejected(this.value)
          } catch (error) {
            onRejected(error)
          }
        }
      })
    }


    if (this.status == Promise2.RESOLVED) {
      setTimeout(() => {
        try {
          onResolved(this.value)
        } catch (error) {
          onRejected(error)
        }
      });

    }

    if (this.status == Promise2.REJECTED) {
      setTimeout(() => {
        try {
          onRejected(this.value)
        } catch (error) {
          onRejected(error)
        }
      });
    }
  }
}


const p1 = new Promise2((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 500);
}).then(res => {
  console.log('res', res); // res 1
})

实现 .then 的链式调用

只需要再 then 方法里 return new Promise2 即可。
这里需要执行 onResolved(value) 后获取 返回值res,并调用 resolve(res)。

class Promise2 {
  static PENDING = 'pending'
  static RESOLVED = 'resolved'
  static REJECTED = 'rejected'

  constructor(executor) {
    this.status = Promise2.PENDING
    this.value = ''
    this.callbacks = []
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }

  resolve(val) {
    if (this.status == Promise2.PENDING) {
      this.status = Promise2.RESOLVED
      this.value = val

      for (var i = 0; i < this.callbacks.length; i++) {
        this.callbacks[i].onResolved(this.value)
      }
    }
  }

  reject(val) {
    if (this.status == Promise2.PENDING) {
      this.status = Promise2.REJECTED
      this.value = val

      for (var i = 0; i < this.callbacks.length; i++) {
        this.callbacks[i].onRejected(this.value)
      }
    }
  }

  then(onResolved, onRejected) {
    // 根据标准,then 的参数需要是函数
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    if (typeof onRejected !== 'function') {
      onRejected = value => value
    }

    // 新增
    return new Promise2((resolve, reject) => {
      if (this.status == Promise2.PENDING) {
        this.callbacks.push({
          onResolved: (value) => {
            try {
              const res = onResolved(value)
              resolve(res)
            } catch (error) {
              const res = onRejected(error)
              reject(res)
            }
          },
          onRejected: (value) => {
            try {
              const res = onRejected(value)
              reject(res)
            } catch (error) {
              const res = onRejected(error)
              reject(res)
            }
          }
        })
      }


      if (this.status == Promise2.RESOLVED) {
        setTimeout(() => {
          try {
            const res = onResolved(this.value)
            resolve(res)
          } catch (error) {
            const res = onRejected(error)
            reject(res)
          }
        });

      }

      if (this.status == Promise2.REJECTED) {
        setTimeout(() => {
          try {
            const res = onRejected(this.value)
            reject(res)
          } catch (error) {
            const res = onRejected(error)
            reject(res)
          }
        });
      }
    })

  }
}


const p1 = new Promise2((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 500);
}).then(res => {
  console.log('res', res);
  return 2
}).then(res => {
  console.log('res2', res);
  return 3
})

Promise then中回调为什么是异步执行?

Promise 的机制就是 then 回调函数必须异步执行。为什么?因为这样保障了代码执行顺序的一致性。
先看一个场景:

promise.then(function(){ 
  if (trueOrFalse) { 
    // 同步执行 
    foo(); 
  } else { 
    // 异步执行 (如:使用第三方库)
     setTimeout(function(){ 
        foo(); 
     }) 
  } 
}); 

bar();
  1. 如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行?
    答案是,如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。
    在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。
  2. 如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行?
    答案一目了然,bar() 先执行,foo() 后执行。

所以为了保证代码执行顺序的一致性, then 回调必须保证是异步的。