一步一步手写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的状态从 pending
到 resolved
/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。。只是为了区分实际的参数和形式参数。不想把人绕进去
我们现在的代码是达不到的。。。怎么做呢。。下篇文章见。。
还没有评论,来说两句吧...