一步一步手写promise[一]

开始之前,假设你对promise有个大致的了解,或者快速读一下Promise A+ 规范,过一下即可,对promise熟练使用,那直接跳过吧。可以边实现,边阅读就行。 不保证实现全部遵循这个规范,但是大致流程肯定要按照这个规范来。

我们看一个基础的原生promise

   var p1 = new Promise((resolve, reject) => {})
   var p2 = new Promise((resolve , reject) => { resolve(1) })
   var p3 = new Promise((resolve, reject) => { reject(2) })
   console.log(p1,  p2,  p3) 

promise 有 pending rejected resolved 3个状态。

promise的状态必须再调用resolve函数之后才变为resolved,必须调用了传入的reject函数才能变为rejected

并且状态不可逆并且只能由pending —> rejected 或者 pending—>resolved

开始撸代码:

function Promise1(executor) {
  this.status = "pending" // resolved rejected pending

  // 这里的 executor 里面的两个参数只是外界的构造函数的参数的函数的形式参数
  // 比如我们这样写 new Promise((resolve, reject) => { console.log('111') })
  // 下面的resolve实际上是在promise内部实现的函数,我们在这里完全可以改为resolve1 reject1
  // 这样命名是为了将形式参数,与实际函数内部的实现分开,其实你完全可以写成一样的,但是那样只会让人头大
  executor(resolve1, reject1)

  // resolve之后,状态应该用 pending 到 resolved
  function resolve1() {
    if (this.status === 'pending') {
      this.status = 'resolved'
    }
  }
  function reject1() {
    if (this.status === 'pending') {
      this.status = 'rejected'
    }
  }
}

到这里我们有一个基础的形式了,于是乎我们这样调用:

var p1 = new Promise1((resolve, reject) => {
  resolve(1)
})
console.log(p1) // oops,status没有变化,发现问题了吗?

是的,resolve1函数和reject1函数里面this对象并不是Promise1实例,错了几次这,这个错误专门记下来 ( ╯□╰ ),当然你可以使用ES6语法或者用临时变量来避免类似错误,我们直接修改成箭头函数吧:

function Promise2(executor) {
  this.status = 'pending'
  var resolve1 = () => {
    if (this.status === 'pending') {
      this.status = 'resolved'
    }
  }
  var reject1 = () => {
    if (this.status === 'pending') {
      this.status = 'rejected'
    }
  }
  executor(resolve1, reject1) // 形式参数
}

var p2 = new Promise2((resolve, reject) => {
  resolve(1)
})
console.log(p2) // 这哈就对了

我们再加一个功能,因为我们一般resolve(),reject()会传递值和错误信息给then的回调。是谁去调用then呢,就是当下的promise;

then方法接收一个两个参数,一个onFulfilled函数和onRejected函数,如果promise从pending->resolved时候resolve(xx)传递了一个值,那么then方法的第一个函数能够获取到,同理reject(yyy)传递的yyy那么then方法的第二个函数也能获取到,如下面那样。

var p1 = new Promise((resolve, reject) => {
	resolve(1)
})
p1.then((val)=> {console.log(val)})

var p2 = new Promise((resolve, reject) => {
	reject(new Error("something wrong"))
})
p2.then(()=>{}, (err)=>{console.error(err)})

那么我们给构造函数增加一个value 和error值,确保实例能够获取到这两个值。

function Promise3(executor) {
	this.status = 'pending'
	this.error = null
	this.value = null
	
	const resolve1 = (resolveValue) =>{
		this.value = resolveValue
		if (this.status === 'pending'){
			this.status = 'resolved'
		}
	}
	const reject1 = (rejectError) => {
		this.error = rejectError
		if (this.status === 'pending') {
			this.status = 'rejected'
		}
	}

	executor(resolve1, reject1)
}

// onFulfilled 为第reolve之后的回调
Promise3.prototype.then = function(onFulfilled, onRejected) {
	const  { error , value  }  = this
    // 若是同步
	// 这里要做一个判断 如果是resolved才去调用onFulfilled, 如果是rejected去调用onRejected
	if ( this.status === 'resolved' ) {
		onFulfilled(value)
	}
	if ( this.status === 'rejected' ) {
		onRejected(error)
	}

}

到这一步就完成了,我们实验一下

var p3 = new Promise3((resolve, reject) => {
  resolve(1)
})
console.log(p3, p3.status)

p3.then((val) => console.log(val))

p3.then((val) => console.log(val, "val22"))

达到了我们预期的效果,我们已经实现了这些功能, 构造一个Promise对象 p, 同步或者异步将p的状态从 pendingresolved /rejected。 并且同步执行resolve或者reject函数,能够在then方法里面正确处理状态变化结果的函数,也能够接收到参数。


但是问题来了。。。我们是立即resolve,将promise的状态从pending修改为resolved,但是若是异步的该怎么做呢?
也就是我们必须要保证异步的resolve执行之后,状态才能变为resolved,才能执行then里面的第一个函数。

要实现这样的效果:

var p3 = new Promise((resolve, reject) => {
	setTimeout(resolve, 200)
}).then(()=>{
	console.log("2s 之后 打印这个信息。。。。")
})

resolve1 和 reject1也可以命名成resolveInner/rejectInner 或者 _reslove / _reject。。只是为了区分实际的参数和形式参数。不想把人绕进去

我们现在的代码是达不到的。。。怎么做呢。。下篇文章见。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值