废话不多说,直接上代码,水平有限,欢迎大家一起讨论!
基本思想:使用异步队列存储处理函数,再根据传入的fn来改变Promise的状态,调用相应队列里的处理函数。
function Promise(fn) {
//初始化
this.status = 'PENDING'
this.value = undefined
this.successQueues = [] //保存成功回调的队列
this.failQueues = [] //保存失败回调的队列
this.finalQueues = [] //保存始终回调的队列
fn(this.resolve.call(this), this.reject.call(this)) //执行传入函数
}
Promise.prototype = {
constructor: Promise,
resolve: function(data) {
if (this.status !== 'PENDING') return
this.status = 'SUCCESS'
this.value = data
this.notify('successQueues')
},
reject: function(err) {
if (this.status !== 'PENDING') return
this.status = 'FAIL'
this.value = err
this.notify('failQueues')
},
//收集处理函数
then: function() {
if (this.status !== 'PENDING') return this
let success = arguments[0] //成功回调
let error = arguments[1] //失败回调
if (success && typeof success === 'function') {
this.successQueues.push(success)
}
if (error && typeof error === 'function') {
this.failQueues.push(error)
}
return this
},
catch: function(callback) {
if (this.status !== 'PENDING') return this
if (callback && typeof callback === 'function') {
this.failQueues.push(callback)
}
return this
},
finally: function(callback) {
if (this.status !== 'PENDING') return this
if (callback && typeof callback === 'function') {
this.finalQueues.push(callback)
}
return this
},
notify: function(type) {
setTimeout(() => {
this[type].forEach(fn => {
fn(this.value)
})
if (this.finalQueues.length > 0) {
this.finalQueues.forEach(fn => {
fn()
})
}
}, 0)
}
}
Promise.resolve = function(data) {
return new Promise(res => {
res(data)
})
}
Promise.reject = function(err) {
return new Promise((res, rej) => {
rej(err)
})
}
Promise.all = function(queues) {
if (!(Symbol.iterator in queues))
throw new Error(`${queues} must be iterator`)
var len = queues.length
var index = 0
var arr = []
return new Promise((res, rej) => {
for (var i = 0; i < len; i++) {
if (quenens[i] instanceof Promise) {
quenens[i]
.then(data => {
index++
arr.push(data)
if (index === len) res(arr)
})
.catch(err => {
rej(err)
})
} else {
Promise(queues[i])
.then(data => {
index++
arr.push(data)
if (index === len) res(arr)
})
.catch(err => {
rej(err)
})
}
}
})
}
Promise.race = function(queues) {
if (!(Symbol.iterator in queues))
throw new Error(`${queues} must be iterator`)
return new Promise((res, rej) => {
for (var i = 0; i < queues.length; i++) {
if (queues[i] instanceof Promise) {
queues[i]
.then(data => {
res(data)
})
.catch(err => {
rej(err)
})
} else {
Promise.resolve(queues[i])
.then(data => {
res(data)
})
.catch(err => {
rej(err)
})
}
}
})
}