首先简单看一下promiseA+规范
(1)Promise对象代表一个异步操作,有三种状态 :pending(进行中)、fulfilled(已成功)和 rejected(已失败)。一旦成功就不允许失败,一旦失败就不允许成功
这里的代码可以这样写
function MyPromise(){ //构造函数所以首字母大写
const self = this
self.status = 'pending'
self.value = null
self.reason = null
}
(2)Promise接收一个函数作为参数,该函数有两个参数,一个是resolve,表示成功时执 行的函数,一个是reject,表示失败失败时执行的函数。 resolve执行时传入的参数会作为then方法中第一个回调函数的参数,reject执行传入的参数会作为then方法中第二函数回调的参数。
我们来补充一下上面的myPromise构造函数
function MyPromise(excutor){
const self = this
self.status = 'pending'
self.value = null
self.reason = null
function resolve(value){ // resolve函数接受成功时传的参数
if(self.status==='pending'){
self.status = 'fulfailled' //改变当前执行函数的状态为成功状态
self.value= value //存储成功时的值
}
}
function reject(reason){ // reject函数接受失败时传的参数
if(self.status==='pending'){
self.status = 'rejected' //改变当前执行函数的状态为失败的状态
self.resaon = reason // 存储失败时的值
}
}
excutor(resolve,reject)
}
// 此时在控制台输出myPromise实例 例如
const mp1 = new MyPromise((resolve,reject)=>{
resolve('test');
// reject('testerror')
})
console.log(mp1)
// 会输出
MyPromise{
reason: null
status: "fulfailled"
value: "test"
}
or
MyPromise{
reason: 'teserror'
status: "rejected"
value: null
}
是不是有点头绪了
把MyPromsie对象里面的 vaule和reason传到then的第一个函数和第二个函数的参数里面就可以了
那我们来实现一下then
//挂载在原型是为了每一个new MyPromise()都可以使用
MyPromise.prototype.then = function(onFulfailled, onRejected){
const self = this
if(self.status==='fulfailled'){
onFulfailled(self.value)
}
if(self.status==='rejected'){
onRejected(self.reason)
}
}
// ok此时then里面就可以接受resolve传的value和reject传的reason
new MyPromise((resove,reject)=>{
resolve('test1')
}).then(res=> {
console.log(res)
}) //此时控制台会打出test1
好了到此一个同步版本的promise就实现的差不多了 我们来看看还剩下的问题
1,异步处理
比如还是上面的例子
//使用setimeout模拟异步
new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('test1')
},1000)
}).then(res=>{
console.log(res)
}) //此时控制台无输出
那我们先来解决这个问题,首先这里then里面没有获取到setimeout里面的resolve的值, 是因为then在setTimeout之前就执行了,现在只要让then可以确保一定在setTimeout执行之后可以拿到resolve里面传的值就可以了。
那怎么解决这个问题呢? 我们是不是先把then的方法存储起来,然后再promise实例执行完的时候去再去执行then里面存储的方法并且把参数传进去
我们先来用两个数组存储成功和失败的方法,改造一下MyPromise构造函数
function MyPromise(excutor){
const self = this
self.status = 'pending'
self.value = null
self.reason = null
self.onFulfailledCallbacks = [] //存储成功的方法
self.onRejectedCallbacks = [] //存储失败的方法
function resolve(value){ // resolve函数接受成功时传的参数
if(self.status==='pending'){
self.status = 'fulfailled' //改变当前执行函数的状态为成功状态
self.value= value //存储成功时的值
self.onFulfailledCallbacks.forEach(item=>item(self.value))
// promise实例状态成功,执行之前存储成功方法的数组,把传给resolve的参数传进去
}
}
function reject(reason){ // reject函数接受失败时传的参数
if(self.status==='pending'){
self.status = 'rejected' //改变当前执行函数的状态为失败的状态
self.resaon = reason // 存储失败时的值
self.onRejectedCallbacks.forEach(item=>item(self.reason))
//promise实例状态失败,执行之前存储成功方法的数组把传给reject的参数传进去
}
}
excutor(resolve,reject)
}
我们再来改造一下then方法
MyPromise.prototype.then = function(onFulfailled, onRejected){
const self = this
if(self.status==='fulfailled'){
onFulfailled(self.value)
}
if(self.status==='rejected'){
onRejected(self.reason)
}
if(self.staus==='pending'){
//处于pending状态也就是promsie实例还在执行的时候,异步状态情况下
self.onFulfailledCallbacks.push(onFulfailed)
self.onRejectedCallbacks.push(onRejected)
}
}
自此myPromise就支持异步了
//改造后,使用setimeout模拟异步
new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('test1')
},1000)
}).then(res=>{
console.log(res)
}) //此时控制台输出test1
2,异常怎么处理,我们的promise有reject去处理异常,我们肯定希望我们所有是的异常都是通过这个函数处理,而不是系统报错
我们再改造一下MyPromise用try,catch来捕获异常,发现异常交给reject处理
function MyPromise(excutor){
const self = this
self.status = 'pending'
self.value = null
self.reason = null
self.onFulfailledCallbacks = [] //存储成功的方法
self.onRejectedCallbacks = [] //存储失败的方法
function resolve(value){ // resolve函数接受成功时传的参数
if(self.status==='pending'){
self.status = 'fulfailled' //改变当前执行函数的状态为成功状态
self.value= value //存储成功时的值
self.onFulfailledCallbacks.forEach(item=>item(self.value))
// promise实例状态成功,执行之前存储成功方法的数组,把传给resolve的参数传进去
}
}
function reject(reason){ // reject函数接受失败时传的参数
if(self.status==='pending'){
self.status = 'rejected' //改变当前执行函数的状态为失败的状态
self.resaon = reason // 存储失败时的值
self.onRejectedCallbacks.forEach(item=>item(self.reason))
//promise实例状态失败,执行之前存储成功方法的数组把传给reject的参数传进去
}
}
try{
excutor(resolve,reject) //如果没有错直接执行
} catch(error) {
reject(error) //一旦发现错误,直接扔给reject函数
}
}
//加上then的完整代码
MyPromise.prototype.then = function(onFulfailled, onRejected){
const self = this
if(self.status==='fulfailled'){
onFulfailled(self.value)
}
if(self.status==='rejected'){
onRejected(self.reason)
}
if(self.staus==='pending'){
//处于pending状态也就是promsie实例还在执行的时候,异步状态情况下
self.onFulfailledCallbacks.push(onFulfailed)
self.onRejectedCallbacks.push(onRejected)
}
}
我们测试一下
//改造后,使用setimeout模拟异步
new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(test1) // 没加'',表示变量但这个变量我们没有定义过
},1000)
}).then(res=>{
console.log(res)
}, error=>{
console.log(error)
}) //此时控制台输出ReferenceError: test1 is not defined,成功通过reject返回了错误信息
此版本只是根据个人理解实现的一个简单版本,跟原版peomise想去甚远,也还有很多功能没有实现,只是抛砖引玉一下,感兴趣的可以自己按照promiseA+规范去实现一下,网上也有一大堆现成的实现(本文github地址:github.com/chuanHH/Blo…),后续可能会出一个完整版的promise