本文有点长。。
** 先看一个最简陋的promise **
```
let p=new Promise(function(resolev,reject){
console.log('执行')
})
```
##### 这时会在浏览器打出 “执行”.... 从这里可以推断出promise的结构应该是: #####
###### 定义promise,传递一个参数,这个参数 是一个函数 并包含两个方法 resolve,reject,这个函数在promise内部是立即执行的 ######
```
function Promise(executor){
function resolve(){ }
function reject(){ }
//其实可以把这个executor看成是一个自执行函数
/*
类似
(function(resolev,reject){
console.log('执行')
})(resolve,reject)
*/
executor(resolve,reject)
}
```
******
##### promise有三种状态, pending(等待状态),resolved(成功状态),rejected(失败状态),而且状态一经改变就不会再变~所以只会有两种情况
##### pending——————>resolved 等待——————>成功 成功了就不能失败...
##### pending——————>rejected 等待——————>失败 失败了就不能成功...ರ_ರ
```
//原生promise
let p=new Promise(function(resolev,reject){
//只会调用最前面的这个
resolve(100)
rejecte(200)
})
p.then(function(data){
console.log(data,'resolved')
},function(error){
console.log(error,'rejecte')
})
```
##### 原生promise中,resolve和reject 只会调用其中在最前面的一个。。并且调用resolve会执行then中的第一个回调,调用reject会执行then中的第二个回调 #####
##### 要实现这样的效果需要在我们自己的promise函数内 #####
* 定义 status,存储当前的状态
* 定义 value, 存储resolve成功 调用时传过来的值
* 定义 reason,存储 reject失败 调用的报错信息
* 定义一个then函数,并接收两个类型为函数的参数,第一个是成功的回调,第二个是失败的回调
* 从promise中的 then方法可以看出~这两个方法只有一个会被执行
** **
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
}
}
executor(resolve, reject)
}
Promise.prototype.then = function (infulfilled, inrejected) {
//由status決定,只有一个方法会被执行
if (this.status == 'resolved') {
infulfilled(this.value)
}
if (this.status == 'rejected') {
inrejected(this.reason)
}
}
```
#### 现在这个promise已经有点样子了..但是离完善还差了很远~因为promise的亮点就是解决异步回调地狱的问题,但是这个手写的promise只支持同步代码,例子如下:
```
//用了自己的promise~不是原生的~~~!
let p = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(100)
},1000)
})
//控制台没有打印任何东西
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject')
})
```
可以看到,这里的then方法没有执行,为什么呢~~~
###### 其实已经执行过了..只是因为现在的状态还是pending等待态。。。并不满足两个if条件里的任何一个。。所以直接略过了,
###### 现在来分析下为什么会这样呢
* 当我们 ` new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(100)
},1000)
})` 的时候 `executor()`会立即执行,不过别忘了这有个 `setTimeout`,所以`executor()`里面的动作 需要等1000ms
* 但是~由于同步函数比异步函数快的原因,所以这时`then`方法开始执行了,然而这时 `Promise`内部的`status`仍然是`pending`等待状态,`then`方法扫描了一下内部...发现status不满足任何一个条件,so..it's ending...结束
* 1000ms过后,`executor()`中的`resolve`开始执行了, 它把`status`改成了`resolved`,把值赋给了`value`..然而并没有后续动作了,so..it's ending...
***
#### 让自己的promise支持异步调用
* 在 promise中定义两个数组 onResovedCallbacks,和 onRejectedCallbacks,用来存放成功和失败的回调函数
* 在then中判断`status` 如果是 `pending`等待状态 ,那就把成功的回调和失败的回调分别存到上面两个数组内
* 在promise的resolve和reject方法中分别遍历onResovedCallbacks和onRjectedCallbacks,执行其中的方法,代码如下
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
//遍历,执行其中的infulfilled()方法
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
//遍历,执行其中的inRejected()方法
self.onRejectedCallbacks.forEach(fn => fn())
}
}
executor(resolve, reject)
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
if (this.status == 'resolved') {
infulfilled(this.value)
}
if (this.status == 'rejected') {
inrejected(this.reason)
}
if (this.status == 'pending') {
//这时既不是resolved也是不是rejected状态
this.onResolvedCallbacks.push(function () {
infulfilled(self.value)
})
this.onRejectedCallbacks.push(function () {
inrejected(self.reason)
})
}
}
let p = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(100)
}, 2000)
})
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject')
})
```
现在可以试一下`setTimeout` ,嗯~已经支持异步调用了~
##### 不过还有一种情况,就是当`new Promise()`中抛出了异常,例如
```
let p = new Promise(function (resolve, reject) {
throw new Error('错误')
})
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject')
})
```
这种情况下 then方法中,成功和失败的回调函数也不会被调用,只会报个错,因为现在的`status`还是`pending`那就需要我们在promise函数内部捕获一下异常 :
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
self.onRejectedCallbacks.forEach(fn => fn())
}
}
//捕获到异常就直接失败了...
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
if (this.status == 'resolved') {
infulfilled(this.value)
}
if (this.status == 'rejected') {
inrejected(this.reason)
}
if (this.status == 'pending') {
this.onResolvedCallbacks.push(function () {
infulfilled(self.value)
})
this.onRejectedCallbacks.push(function () {
inrejected(self.reason)
})
}
}
let p = new Promise(function (resolve, reject) {
throw new Error('错误')
})
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject111')
})
```
##### 现在已经可以成功捕获异常了
***
现在手写的promise离原生的promise又更像了一点,但是原生最大的特点~链式调用,我们还没有实现,
##### 分析下~链式调用的实现方法
#### 为了保证链式调用,不管是成功/失败/等待状态,都要返回一个新的`Promise`才能继续调用then方法
##### 所以声明一个promise2=新的`Promise`去 解析,当new Promise的时候会立即执行executor
![](https://user-gold-cdn.xitu.io/2018/5/20/1637b13c20f816c5?w=1792&h=935&f=png&s=242916)
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
self.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
infulfilled(self.value)
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
inrejected(self.reason)
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
infulfilled(self.value)
})
self.onRejectedCallbacks.push(function () {
inrejected(self.reason)
})
})
}
return promise2
}
```
这段代码看起来很简单~嗯~~~就是返回一个新的promise嘛~
#### 其次~原生promise规定在then中无论是成功的回调还是失败的回调,只要返回了结果就会进入下一个then的成功的回调,如果有异常就会进入下一个then的失败的回调.
##### 先来看一下then在抛出异常后的处理
*** 先看下面一段代码
```
//原生的promise和现在手写的promise都能实现这个功能哦~
let p = new Promise(function (resolve, reject) {
resolve(1000)
//reject(2000)
})
let p2 = p.then(function (data) {
throw new Error('錯誤')
}, function (error) {
throw new Error('失败了')
})
p2.then(function (data) {
console.log(data, 'resolve');
}, function (error) {
console.log(error, 'rejected');
})
```
可以看到,无论是在promise实例中使用了 `resolve()`还是`reject()`只要,在`then`中抛出了异常,就会进入下一个`then`的失败的回调
##### 一步步分解下这个捕获异常的执行流程,先上个图
![](https://user-gold-cdn.xitu.io/2018/5/19/1637677d6c6c17f6?w=1470&h=949&f=png&s=180264)
##### 捋一下图片里的思路 #####
* 第一步
```
//先调用了resolve,所以现在的promise的status是resolved 成功态
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
```
* 第二步 调用`then`方法,`then`方法中 根据当前的状态 `resolved`进入第一个`if`条件中
* 2.1 新初始化了一个Promise实例
* 2.2 新的Promiese实例会立即执行 `infulfilled`被调用,但是现在infulfilled里抛出了异常,被新的`promise` `try catch`捕获到,然后reject方法被调用,新的`promise`状态 `status`被改成`reject`失败状态, `reason`等于被`catch`到的报错信息
```
let p2 = p.then(function (data) {
throw new Error('錯誤')
}, function (error) {
throw new Error('失败了')
})
```
* 第三步, 现在 p2就是那个新的promise,并且状态是`reject` `reason`是刚捕获到的报错信息,当它调用then方法时进入第二个if条件,因为当前状态是`reject`嘛,
* 3.1 新初始化一个Promise实例
* 3.2 Promise立即执行,inrejected方法被调用,即p2.then的第二个回调函数执行。。打印错误信息
```
p2.then(
function (data) {
console.log(data, 'resolve');
},
function (error) {
console.log(error, 'rejected');
})
```
##### 终于把异常处理分析完了。。。
##### 现在来分析下成功,或者失败的返回值的情况,
原生的`primse`执行`then`方法,有时可能会返回一个结果,作为下一个promise的值`value`或失败的原因`reason`,这个结果可能是一个普通值也可能是一个promise
```
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
let p2 = p.then(function (data) {
//返回一个普通值
// return 'test'
//返回一个promise
return new Promise(function (resolve, reject) {
//resolve('成功')
reject('失败')
})
}, function (error) {
throw new Error('failed')
})
p2.then(
function (data) {
console.log(data, 'resolveq');
},
function (error) {
console.log(error, 'rejected ');
})
```
为了实现这个效果,要完善一下手写的`Promise`的`then`方法,写一个函数`resolvePromise`统一处理`then`方法执行后返回的结果
```
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
self.onRejectedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
})
}
return promise2
}
```
resolvePromise的内部实现
* 1.首先看一种情况,
在原生Promise中 then方法返回的结果可能是他本身,这种情况永远不会成功或者失败(循环引用),这时会抛出一个类型错误的异常
![](https://user-gold-cdn.xitu.io/2018/5/20/1637b41cd2ac3dab?w=1360&h=460&f=png&s=37762)
所以在 resolvePromise内部要判断 返回的结果和Promise是不是同一个
* 2.判断 x是不是一个`promise`,如果是`promise`,如果x是对象,并且x的then方法是函数,那它就是promise
* 3 如果x不是`promise` 那应该是普通值 直接`resolve`
* 4.如果x是一个`promise`,那就看下他有没有`then`方法
```
function resolvePromise(p2, x, resolve, reject) {
if (p2 === x && x != undefined) {
reject(new TypeError('类型错误'))
}
//可能是promise,看下对象中是否有then方法,如果有~那就是个promise
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {//为了防止出现 {then:11}这种情况,需要判断then是不是一个函数
let then = x.then
if (typeof then === 'function') {
then.call(x, function (y) {
//y 可能还是一个promise,那就再去解析,知道返回一个普通值为止
resolvePromise(p2, y, resolve, reject)
}, function (err) {
reject(err)
})
} else {//如果then不是function 那可能是对象或常量
resolve(x)
}
} catch (e) {
reject(e)
}
} else {//说明是一个普通值
resolve(x)
}
}
```
再完善一下..我们的代码应该可以在then中什么都不传,实现值得穿透
```
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
p.then().then().then(function (data) {
console.log(data, 'resolve');
}, function (error) {
console.log(error, 'reject');
})
```
所以在then方法中需要对接收的参数`infulfilled`, `inrejected`进行容错 处理,
对于`infulfilled` 有就用原参数,没有就给个默认的函数
对于`inrejected` 没有就抛出异常
```
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
//如果infulfilled不是function就给个默认函数,返回val
infulfilled = typeof infulfilled === 'function' ? infulfilled : function (val) {
return val
}
//如果inrejected不是函数就抛出异常
inrejected = typeof inrejected === 'function' ? inrejected : function (err) {
throw err
}
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
})
self.onRejectedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
})
})
}
return promise2
}
```
最后~promise规范中要求所有的`infulfilled`, `inrejected`都要异步执行,所以这里给所有的`infulfilled`, `inrejected`加上setTimeout,下面是完整代码:
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
self.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
infulfilled = typeof infulfilled === 'function' ? infulfilled : function (val) {
return val
}
inrejected = typeof inrejected === 'function' ? inrejected : function (err) {
throw err
}
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
self.onRejectedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
})
}
return promise2
}
function resolvePromise(p2, x, resolve, reject) {
if (p2 === x && x != undefined) {
reject(new TypeError('类型错误'))
}
//可能是promise,看下对象中是否有then方法,如果有~那就是个promise
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {//为了防止出现 {then:11}这种情况,需要判断then是不是一个函数
let then = x.then
if (typeof then === 'function') {
then.call(x, function (y) {
//y 可能还是一个promise,那就再去解析,知道返回一个普通值为止
resolvePromise(p2, y, resolve, reject)
}, function (err) {
reject(err)
})
} else {//如果then不是function 那可能是对象或常量
resolve(x)
}
} catch (e) {
reject(e)
}
} else {//说明是一个普通值
resolve(x)
}
}
```
ok~promise写完了。。欢迎大家提出建议。。
** 先看一个最简陋的promise **
```
let p=new Promise(function(resolev,reject){
console.log('执行')
})
```
##### 这时会在浏览器打出 “执行”.... 从这里可以推断出promise的结构应该是: #####
###### 定义promise,传递一个参数,这个参数 是一个函数 并包含两个方法 resolve,reject,这个函数在promise内部是立即执行的 ######
```
function Promise(executor){
function resolve(){ }
function reject(){ }
//其实可以把这个executor看成是一个自执行函数
/*
类似
(function(resolev,reject){
console.log('执行')
})(resolve,reject)
*/
executor(resolve,reject)
}
```
******
##### promise有三种状态, pending(等待状态),resolved(成功状态),rejected(失败状态),而且状态一经改变就不会再变~所以只会有两种情况
##### pending——————>resolved 等待——————>成功 成功了就不能失败...
##### pending——————>rejected 等待——————>失败 失败了就不能成功...ರ_ರ
```
//原生promise
let p=new Promise(function(resolev,reject){
//只会调用最前面的这个
resolve(100)
rejecte(200)
})
p.then(function(data){
console.log(data,'resolved')
},function(error){
console.log(error,'rejecte')
})
```
##### 原生promise中,resolve和reject 只会调用其中在最前面的一个。。并且调用resolve会执行then中的第一个回调,调用reject会执行then中的第二个回调 #####
##### 要实现这样的效果需要在我们自己的promise函数内 #####
* 定义 status,存储当前的状态
* 定义 value, 存储resolve成功 调用时传过来的值
* 定义 reason,存储 reject失败 调用的报错信息
* 定义一个then函数,并接收两个类型为函数的参数,第一个是成功的回调,第二个是失败的回调
* 从promise中的 then方法可以看出~这两个方法只有一个会被执行
** **
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
}
}
executor(resolve, reject)
}
Promise.prototype.then = function (infulfilled, inrejected) {
//由status決定,只有一个方法会被执行
if (this.status == 'resolved') {
infulfilled(this.value)
}
if (this.status == 'rejected') {
inrejected(this.reason)
}
}
```
#### 现在这个promise已经有点样子了..但是离完善还差了很远~因为promise的亮点就是解决异步回调地狱的问题,但是这个手写的promise只支持同步代码,例子如下:
```
//用了自己的promise~不是原生的~~~!
let p = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(100)
},1000)
})
//控制台没有打印任何东西
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject')
})
```
可以看到,这里的then方法没有执行,为什么呢~~~
###### 其实已经执行过了..只是因为现在的状态还是pending等待态。。。并不满足两个if条件里的任何一个。。所以直接略过了,
###### 现在来分析下为什么会这样呢
* 当我们 ` new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(100)
},1000)
})` 的时候 `executor()`会立即执行,不过别忘了这有个 `setTimeout`,所以`executor()`里面的动作 需要等1000ms
* 但是~由于同步函数比异步函数快的原因,所以这时`then`方法开始执行了,然而这时 `Promise`内部的`status`仍然是`pending`等待状态,`then`方法扫描了一下内部...发现status不满足任何一个条件,so..it's ending...结束
* 1000ms过后,`executor()`中的`resolve`开始执行了, 它把`status`改成了`resolved`,把值赋给了`value`..然而并没有后续动作了,so..it's ending...
***
#### 让自己的promise支持异步调用
* 在 promise中定义两个数组 onResovedCallbacks,和 onRejectedCallbacks,用来存放成功和失败的回调函数
* 在then中判断`status` 如果是 `pending`等待状态 ,那就把成功的回调和失败的回调分别存到上面两个数组内
* 在promise的resolve和reject方法中分别遍历onResovedCallbacks和onRjectedCallbacks,执行其中的方法,代码如下
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
//遍历,执行其中的infulfilled()方法
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
//遍历,执行其中的inRejected()方法
self.onRejectedCallbacks.forEach(fn => fn())
}
}
executor(resolve, reject)
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
if (this.status == 'resolved') {
infulfilled(this.value)
}
if (this.status == 'rejected') {
inrejected(this.reason)
}
if (this.status == 'pending') {
//这时既不是resolved也是不是rejected状态
this.onResolvedCallbacks.push(function () {
infulfilled(self.value)
})
this.onRejectedCallbacks.push(function () {
inrejected(self.reason)
})
}
}
let p = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(100)
}, 2000)
})
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject')
})
```
现在可以试一下`setTimeout` ,嗯~已经支持异步调用了~
##### 不过还有一种情况,就是当`new Promise()`中抛出了异常,例如
```
let p = new Promise(function (resolve, reject) {
throw new Error('错误')
})
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject')
})
```
这种情况下 then方法中,成功和失败的回调函数也不会被调用,只会报个错,因为现在的`status`还是`pending`那就需要我们在promise函数内部捕获一下异常 :
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
self.onRejectedCallbacks.forEach(fn => fn())
}
}
//捕获到异常就直接失败了...
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
if (this.status == 'resolved') {
infulfilled(this.value)
}
if (this.status == 'rejected') {
inrejected(this.reason)
}
if (this.status == 'pending') {
this.onResolvedCallbacks.push(function () {
infulfilled(self.value)
})
this.onRejectedCallbacks.push(function () {
inrejected(self.reason)
})
}
}
let p = new Promise(function (resolve, reject) {
throw new Error('错误')
})
p.then(function (data) {
console.log(data, 'resolve')
}, function (error) {
console.log(error, 'reject111')
})
```
##### 现在已经可以成功捕获异常了
***
现在手写的promise离原生的promise又更像了一点,但是原生最大的特点~链式调用,我们还没有实现,
##### 分析下~链式调用的实现方法
#### 为了保证链式调用,不管是成功/失败/等待状态,都要返回一个新的`Promise`才能继续调用then方法
##### 所以声明一个promise2=新的`Promise`去 解析,当new Promise的时候会立即执行executor
![](https://user-gold-cdn.xitu.io/2018/5/20/1637b13c20f816c5?w=1792&h=935&f=png&s=242916)
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
self.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
infulfilled(self.value)
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
inrejected(self.reason)
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
infulfilled(self.value)
})
self.onRejectedCallbacks.push(function () {
inrejected(self.reason)
})
})
}
return promise2
}
```
这段代码看起来很简单~嗯~~~就是返回一个新的promise嘛~
#### 其次~原生promise规定在then中无论是成功的回调还是失败的回调,只要返回了结果就会进入下一个then的成功的回调,如果有异常就会进入下一个then的失败的回调.
##### 先来看一下then在抛出异常后的处理
*** 先看下面一段代码
```
//原生的promise和现在手写的promise都能实现这个功能哦~
let p = new Promise(function (resolve, reject) {
resolve(1000)
//reject(2000)
})
let p2 = p.then(function (data) {
throw new Error('錯誤')
}, function (error) {
throw new Error('失败了')
})
p2.then(function (data) {
console.log(data, 'resolve');
}, function (error) {
console.log(error, 'rejected');
})
```
可以看到,无论是在promise实例中使用了 `resolve()`还是`reject()`只要,在`then`中抛出了异常,就会进入下一个`then`的失败的回调
##### 一步步分解下这个捕获异常的执行流程,先上个图
![](https://user-gold-cdn.xitu.io/2018/5/19/1637677d6c6c17f6?w=1470&h=949&f=png&s=180264)
##### 捋一下图片里的思路 #####
* 第一步
```
//先调用了resolve,所以现在的promise的status是resolved 成功态
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
```
* 第二步 调用`then`方法,`then`方法中 根据当前的状态 `resolved`进入第一个`if`条件中
* 2.1 新初始化了一个Promise实例
* 2.2 新的Promiese实例会立即执行 `infulfilled`被调用,但是现在infulfilled里抛出了异常,被新的`promise` `try catch`捕获到,然后reject方法被调用,新的`promise`状态 `status`被改成`reject`失败状态, `reason`等于被`catch`到的报错信息
```
let p2 = p.then(function (data) {
throw new Error('錯誤')
}, function (error) {
throw new Error('失败了')
})
```
* 第三步, 现在 p2就是那个新的promise,并且状态是`reject` `reason`是刚捕获到的报错信息,当它调用then方法时进入第二个if条件,因为当前状态是`reject`嘛,
* 3.1 新初始化一个Promise实例
* 3.2 Promise立即执行,inrejected方法被调用,即p2.then的第二个回调函数执行。。打印错误信息
```
p2.then(
function (data) {
console.log(data, 'resolve');
},
function (error) {
console.log(error, 'rejected');
})
```
##### 终于把异常处理分析完了。。。
##### 现在来分析下成功,或者失败的返回值的情况,
原生的`primse`执行`then`方法,有时可能会返回一个结果,作为下一个promise的值`value`或失败的原因`reason`,这个结果可能是一个普通值也可能是一个promise
```
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
let p2 = p.then(function (data) {
//返回一个普通值
// return 'test'
//返回一个promise
return new Promise(function (resolve, reject) {
//resolve('成功')
reject('失败')
})
}, function (error) {
throw new Error('failed')
})
p2.then(
function (data) {
console.log(data, 'resolveq');
},
function (error) {
console.log(error, 'rejected ');
})
```
为了实现这个效果,要完善一下手写的`Promise`的`then`方法,写一个函数`resolvePromise`统一处理`then`方法执行后返回的结果
```
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
self.onRejectedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
//这里的resolve和reject都是promise2的,x就是infulfilled的返回值 可能是一个promise,也可能是个普通值所以要统一处理
resolvePromise(promise2, x, resolve, reject)
})
})
}
return promise2
}
```
resolvePromise的内部实现
* 1.首先看一种情况,
在原生Promise中 then方法返回的结果可能是他本身,这种情况永远不会成功或者失败(循环引用),这时会抛出一个类型错误的异常
![](https://user-gold-cdn.xitu.io/2018/5/20/1637b41cd2ac3dab?w=1360&h=460&f=png&s=37762)
所以在 resolvePromise内部要判断 返回的结果和Promise是不是同一个
* 2.判断 x是不是一个`promise`,如果是`promise`,如果x是对象,并且x的then方法是函数,那它就是promise
* 3 如果x不是`promise` 那应该是普通值 直接`resolve`
* 4.如果x是一个`promise`,那就看下他有没有`then`方法
```
function resolvePromise(p2, x, resolve, reject) {
if (p2 === x && x != undefined) {
reject(new TypeError('类型错误'))
}
//可能是promise,看下对象中是否有then方法,如果有~那就是个promise
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {//为了防止出现 {then:11}这种情况,需要判断then是不是一个函数
let then = x.then
if (typeof then === 'function') {
then.call(x, function (y) {
//y 可能还是一个promise,那就再去解析,知道返回一个普通值为止
resolvePromise(p2, y, resolve, reject)
}, function (err) {
reject(err)
})
} else {//如果then不是function 那可能是对象或常量
resolve(x)
}
} catch (e) {
reject(e)
}
} else {//说明是一个普通值
resolve(x)
}
}
```
再完善一下..我们的代码应该可以在then中什么都不传,实现值得穿透
```
let p = new Promise(function (resolve, reject) {
resolve(1000)
})
p.then().then().then(function (data) {
console.log(data, 'resolve');
}, function (error) {
console.log(error, 'reject');
})
```
所以在then方法中需要对接收的参数`infulfilled`, `inrejected`进行容错 处理,
对于`infulfilled` 有就用原参数,没有就给个默认的函数
对于`inrejected` 没有就抛出异常
```
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
//如果infulfilled不是function就给个默认函数,返回val
infulfilled = typeof infulfilled === 'function' ? infulfilled : function (val) {
return val
}
//如果inrejected不是函数就抛出异常
inrejected = typeof inrejected === 'function' ? inrejected : function (err) {
throw err
}
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
})
self.onRejectedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
})
})
}
return promise2
}
```
最后~promise规范中要求所有的`infulfilled`, `inrejected`都要异步执行,所以这里给所有的`infulfilled`, `inrejected`加上setTimeout,下面是完整代码:
```
function Promise(executor) {
let self = this
this.status = 'pending' //当前状态
this.value = undefined //存储成功的值
this.reason = undefined //存储失败的原因
this.onResolvedCallbacks = []//存储成功的回调
this.onRejectedCallbacks = []//存储失败的回调
function resolve(value) {
if (self.status == 'pending') {
self.status = 'resolved'
self.value = value
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(error) {
if (self.status == 'pending') {
self.status = 'rejected'
self.reason = error
self.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
infulfilled = typeof infulfilled === 'function' ? infulfilled : function (val) {
return val
}
inrejected = typeof inrejected === 'function' ? inrejected : function (err) {
throw err
}
if (this.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
if (this.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
if (this.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = infulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
self.onRejectedCallbacks.push(function () {
//x可能是一个promise,也可能是个普通值
setTimeout(function () {
try {
let x = inrejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
})
}
return promise2
}
function resolvePromise(p2, x, resolve, reject) {
if (p2 === x && x != undefined) {
reject(new TypeError('类型错误'))
}
//可能是promise,看下对象中是否有then方法,如果有~那就是个promise
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {//为了防止出现 {then:11}这种情况,需要判断then是不是一个函数
let then = x.then
if (typeof then === 'function') {
then.call(x, function (y) {
//y 可能还是一个promise,那就再去解析,知道返回一个普通值为止
resolvePromise(p2, y, resolve, reject)
}, function (err) {
reject(err)
})
} else {//如果then不是function 那可能是对象或常量
resolve(x)
}
} catch (e) {
reject(e)
}
} else {//说明是一个普通值
resolve(x)
}
}
```
ok~promise写完了。。欢迎大家提出建议。。