简单实现Promise和链式调用

161 阅读2分钟

🏃🏻 最近复习了一下Promise相关知识点,顺便自己简单的手写实现一个Promise和链式调用

  1. 实现Promise()
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

function MyPromise(fn) {
  this.status = PENDING;
  this.value = null;
  this.reason = null;
  this.resolvedCallbacks = [];
  this.rejectedCallbacks = [];

  const resolve = (value) => {
    if (this.status === PENDING) {
      this.status = RESOLVED;
      this.value = value;

      setTimeout(() => {
        this.resolvedCallbacks.map(cb => cb());
      })

    }
  }

  // reject实现原理同上
  const reject = (reason) => {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.reason = reason;
      setTimeout(() => {
        this.rejectedCallbacks.map(cb => cb());
      })
    }
  }

  try {
    fn(resolve, reject);
  } catch (e) {
    reject(e);
  }
}


// then/catch
MyPromise.prototype.then = function (onFulfilled, onRejected) {
  return new MyPromise((resolve, reject) => {
    this.resolvedCallbacks.push(() => {
      const res = onFulfilled(this.value)
      if (res instanceof MyPromise) {
        res.then(resolve, reject)
      } else {
        resolve(res)
      }
    });

    // reject实现原理同上
    this.rejectedCallbacks.push(() => {
      const res = onRejected(this.reason)
      if (res instanceof MyPromise) {
        res.then(resolve, reject)
      } else {
        reject(res)
      }
    });
  })
}


// 使用
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('successMsg-p');
    // reject('errInfo-p');
  }, 1000);
});
const p1 = p.then((res) => {
  console.log('res:', res)
  return p2
}, (err) => {
  console.log('err: ', err);
})
// user promise
const p2 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('successMsg-p2');
  }, 500)
})


//  链式调用
new MyPromise((resolve) => {
  setTimeout(() => {
    resolve(1)
  }, 5000)
})
  .then((res) => {
    console.log(res);   // 1
    return new MyPromise((resolve) => {   // user promise
      setTimeout(() => {
        resolve(2);
      }, 2000);
    });
  })
  .then(console.log)   // 2
  1. 实现promise.resolve()
// resolve
MyPromise.resolve = function (data) {
  // 1. 参数是一个 Promise 实例,不做任何修改、原封不动地返回这个实例
  if (data instanceOf MyPromise) {
    return data
  }
  // 2. 参数是一个thenable对象,将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
  if (data.then) {
    return new MyPromise((resolve, reject) => {
      data.then(resolve, reject)
    })
  }
  // 3. 参数不是具有then方法的对象,或根本就不是对象
  // 4. 不带有任何参数
  return new MyPromise((resolve) => {
    resolve(data)
  })
}
  1. 实现promise.all()
// all
MyPromise.all = (promises) => {
  let arr = [], count = 0;
  return new Promse((resolve, reject) => {
    promises.forEach((item, i) => {
      MyPromise.resolve(item).then(res => {
        arr[i] = res;
        count += 1;
        if (count === promise.length) resolve(arr)
      }, reject)
    })
  })
}
  1. 实现promise.allSettled()
// allSettled
MyPromise.allSettled = (promised) => {
  let arr = [], count = 0
  const processResult = (res, index, status) => {
    arr[index] = { status: status, val: res }
    count += 1
    if (count === promises.length) resolve(arr)
  }
  promises.forEach((item, i) => {
    MyPromise.resolve(item).then(res => {
      processResult(res, i, 'fulfilled')
    }, err => {
      processResult(err, i, 'rejected')
    })
  })
}
  1. 实现promise.race()
// race
MyPromise.race = (promises) => {
  return new MyPromise((resolve, reject) => {
    promises.forEach((item) => {
      MyPromise.resolve(item).then(resolve, reject)
    })
  })
}
  1. 实现promise.any()
// any
MyPromise.any = (promises) => {
  let arr = [], count = 0;
  return new MyPromise((resolve, reject) => {
    promises.forEach((item, i) => {
      MyPromise.resolve(item).then(resolve, () => {
        arr[i] = { status: 'rejected', val: err }
        count += 1;
        if (count = arr.length) {
          reject(new AggregateError(arr, 'All promises were rejected'))
        }
      })
    })
  })
}

👉 本代码仅供参考,欢迎各位大佬有好的想法或建议可以留言,后续再回来更改优化~~

(仅考虑了如何简单实现过程,没有考虑太多细节🙌)

✍️ 感兴趣的话可以阅读 Promise A+ 规范 promisesaplus.com/