简介
Promise
基本知识参考:Promise小结
简易版
function MyPromise(executor) {
if (typeof executor !== 'function') {
throw new TypeError('this is not a function')
}
this.cbs = []
const resolve = value => {
this.value = value
this.cbs.forEach(v => v())
}
executor(resolve)
}
MyPromise.prototype.then = function(onResolved) {
typeof onResolved !== 'function' && (onResolved = v => v)
return new MyPromise(resolve => {
this.cbs.push(() => {
const res = onResolved(this.value)
if (res instanceof MyPromise) {
res.then(resolve)
} else {
resolve(res)
}
})
})
}
// 测试
new MyPromise(resolve => {
console.log('promise')
setTimeout(() => {
resolve('resolve')
}, 1000)
}).then(res => {
console.log(res)
return new MyPromise((resolve) => {
setTimeout(() => {
resolve(1)
}, 500)
})
}).then(res => {
console.log(2, res)
})
完整版
const PromiseTypes = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
function MyPromise(executor) {
if (typeof executor !== 'function') throw new TypeError('this is not a function')
this.status = PromiseTypes.PENDING
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
const resolve = value => {
if (this.status === PromiseTypes.PENDING) {
this.value = value
this.status = PromiseTypes.FULFILLED
this.onResolvedCallbacks.forEach(v => v())
}
}
const reject = reason => {
if (this.status === PromiseTypes.PENDING) {
this.reason = reason
this.status = PromiseTypes.REJECTED
this.onRejectedCallbacks.forEach(v => v())
}
}
try {
executor(resolve, reject)
} catch(e) {
console.log('executor, error')
reject(e)
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let promise2
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r }
if (this.status === PromiseTypes.FULFILLED) {
promise2 = new MyPromise((resolve, reject) => {
// onFulfilled(this.value) 要放在try...catch中执行,捕获异常
asyncCallback(promise2, () => onFulfilled(this.value), resolve, reject)
})
}
if (this.status === PromiseTypes.REJECTED) {
promise2 = new MyPromise((resolve, reject) => {
asyncCallback(promise2, () => onRejected(this.reason), resolve, reject)
})
}
if (this.status === PromiseTypes.PENDING) {
promise2 = new MyPromise((resolve, reject) => {
this.onResolvedCallbacks.push(() => {
asyncCallback(promise2, () => onFulfilled(this.value), resolve, reject)
})
this.onRejectedCallbacks.push(() => {
asyncCallback(promise2, () => onRejected(this.reason), resolve, reject)
})
})
}
return promise2
}
function asyncCallback(promise2, cb, resolve, reject) {
setTimeout(() => {
try {
const x = cb()
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'))
}
if (x instanceof MyPromise) {
if (x.status === PromiseTypes.PENDING) {
x.then(v => {
resolvePromise(promise2, v, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
return
}
let called = false
if (x !== null && (typeof x === 'object' || typeof 'x' === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if (called) return
called = true
return resolvePromise(promise2, y, resolve, reject)
}, err => {
if (called) return
called = true
return reject(err)
})
} else {
resolve(x)
}
} catch(e) {
if (called) return
called = true
return reject(e)
}
} else {
resolve(x)
}
}
// 测试
new MyPromise((resolve, reject) => {
console.log('promise')
setTimeout(() => {
resolve('resolve')
}, 1000)
}).then(res => {
console.log(res)
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 500)
})
}).then(res => {
console.log(2, res)
})
参考:剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类
Promise.prototype.catch
MyPromise.prototype.catch = function(fn) {
this.then(null, fn)
}
Promise.prototype.finally
MyPromise.prototype.finally = function(callback) {
const P = this.constructor
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
)
}
Promise.resolve
MyPromise.resolve = function(val) {
return new MyPromise((resolve, reject) => {
resolve(val)
})
}
Promise.reject
MyPromise.reject = function(err) {
return new MyPromise((resolve, reject) => {
reject(err)
})
}
Promise.race
Promise.race([p1, p2, p3])
里面哪个结果获得的快,就返回那个结果,
不管结果本身是成功状态还是失败状态
MyPromise.race = function(arr) {
return new MyPromise((resolve, reject) => {
arr.forEach(item => {
if (item instanceof MyPromise) {
// 处理Promise对象
item.then(resolve, reject)
} else {
// 处理非Promise对象
MyPromise.resolve(item).then(resolve, reject)
}
})
})
}
// 测试
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(11)
}, 2000)
})
const p2 = new MyPromise((resolve, reject) => {
reject('asfs')
});
const p3 = new MyPromise((resolve) => {
setTimeout(() => {
resolve(33)
}, 4)
});
MyPromise.race([p1, p3, 3, 4]).then(data => {
console.log(data)
}, err => {
console.log('失败跑的最快')
})
MyPromise.race([p1, p2, p3, 3, 4]).then(data => {
console.log(data)
}, err => {
console.log('失败跑的最快')
})
Promise.all
获取所有的promise
,都执行then
,把结果放到数组,一起返回
如果出现异常,立即返回异常
MyPromise.all = function(arr) {
return new MyPromise((resolve, reject) => {
if (arr.length === 0) {
resolve([])
return
}
const resArr = []
let count = 0
function processData(index, value) {
resArr[index] = value
count++
if (count === arr.length) {
resolve(resArr)
}
}
arr.forEach((item, index) => {
if (item instanceof MyPromise) {
item.then(value => {
processData(index, value)
}, reject)
} else {
processData(index, item)
}
})
})
}
// 测试
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(11)
}, 2000)
})
const p3 = new MyPromise((resolve) => {
setTimeout(() => {
resolve(33)
}, 4)
})
MyPromise.all([p1, p3, 3, 4]).then(data => {
// 按传入数组的顺序打印
console.log(data) // [ 11, 33, 3, 4 ]
}, err => {
console.log(err)
})
Promise.allSettled
获取所有的promise
,都执行then
,把结果放到数组,一起返回
与
Promise.all
的区别:
Promise.all
是这几个Promise
有个异常的话,立即返回,返回异常allSettled
是等所有的都执行完,再返回。整个过程不会有异常。每个返回的结果中,会有这个Promise
的状态(成功返回还是异常)和返回值(成功的返回值或者原因)
MyPromise.allSettled = function(arr) {
return new MyPromise((resolve, reject) => {
const len = arr.length
const resArr = new Array(len)
let count = 0
function processData(index, data) {
resArr[index] = data
count++
if (count === len) {
resolve(resArr)
}
}
res.forEach((item, index) => {
if (item instanceof MyPromise) {
item.then(value => {
processData(index, { status: 'fulfilled', value })
}, reason => {
processData(index, { status: 'rejected', reason })
})
} else {
processData(index, { status: 'fulfilled', value: item })
}
})
})
}
发表评论