Promise是一种异步请求的处理方案,是es6新增的类,为解决异步函数执行时定下一种规范
function foo() {
return new Promise((resolve, reject) => {
resolve()
})
}
const promise = new Promise((resolve, reject) => {
resolve()
})
const fooPromise = foo()
fooPromise.then((res) => {
console.log(res+'函数1');
}, (error) => {
console.log(error + '函数2');
})
fooPromise.catch(() => {
})
Promise划分为3个状态,分为待定(pending), 已兑现(fulfiled),已拒绝(rejected),状态一旦确定下来,就不可更改
const promise = new Promise((resolve, reject) => {
resolve()
reject()
})
promise.then(res => {
console.log('Promise的状态是fulfiled(固定,已敲定)');
}, err => {
console.log('Promise的状态是rejected(已拒绝)');
})
关于resolve参数,可以传入普通的值和对象也可以传入Promise,如果传入的是Promise,当前Promise的状态会由传入的Promise来决定,如果传入了一个对象,并且该对象有实现then方法,那么也会执行该then方法,由该then方法决定后续状态
const newPromise = new Promise((resolve, reject) => {
resolve('aaaa')
})
const promise1 = new Promise((resolve, reject) => {
resolve(newPromise)
})
promise1.then(res => {
console.log('res: ' + res);
}, err => {
console.log('err: ' + err);
})
const promise2 = new Promise((resolve, reject) => {
const obj = {
then: function (resolve, reject) {
resolve('resolve message')
}
}
resolve(obj)
})
promise2.then(res => {
console.log('res: ' + res);
}, err => {
console.log('err: ' + err);
})
关于Promise的对象方法-then
(1)同一个Promise可以多次调用then方法
const promise = new Promise((resolve, reject) => {
resolve('hahaha')
})
promise.then(res => {
console.log('res1:' + res);
})
promise.then(res => {
console.log('res2:' + res);
})
(2)then方法传入的回调函数可以有返回值,如果返回的是一个普通值,那么这个普通值会被作为一个新的Promise的resolve值。如果我们返回是一个Promise,则会根据传入的Promise的状态决定外层Promise的状态。如果返回的是一个对象,并且该对象实现了thenable
const promise = new Promise((resolve, reject) => {
resolve('hahaha')
})
promise.then(res => {
console.log(res);
return 'aaa'
}).then(res => {
console.log(res);
return 'bbbbb'
}).then(res => {
console.log(res);
})
promise.then(res => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(11111)
}, 3000);
})
}).then(res => {
console.log('res:' + res);
})
promise.then(res => {
return {
then: function (resolve, reject) {
resolve(222222)
}
}
}).then(res => {
console.log(res);
})
(3) 关于Promise的catch方法
const promise = new Promise((resolve, reject) => {
reject("rejected status")
})
promise.then(undefined, (err) => {
console.log(err);
})
promise.catch(err => {
console.log(err);
})
promise.then(res => {
return 1111
}).catch(err => {
console.log(err);
})
(3) 关于Promise的finally方法: 无论是fulfiled还是rejected状态,finally的代码都会执行
const promise = new Promise((resolve, reject) => {
reject("rejected status")
})
promise.then(res => {
console.log(res);
}).catch(err => {
console.log(err);
}).finally(() => {
console.log('finally code execute')
})
关于Promise的类方法
1,Promise的resolve类方法与调用resolve()时相当
2,Promise的reject类方法与调用reject()时相当
3,Promise的all类方法:等多个Promise函数都执行之后回调,返回一个数组,但是有一个函数是返回reject,就只返回该rejece函数
4,Promise的allSettled类方法:,可以执行多个Promise对象,获取多个Promise状态。相比于Promise的all方法,可以获取成功或失败的所有状态
5,Promise的race类方法:返回第一个成功执行的Promise函数
6,Promise的any类方法:返回第一个成功执行的Promise函数,如果所有传入的Promise都失败,则返回异步失败,和一个 AggregateError 对象,它继承自 Error,有一个 errors 属性,属性值是由所有失败值填充的数组。(ES12)
手写Promise的实现
(1)Promise的then方法实现
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HMPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
});
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
return new HMPromise((resolve, reject) => {
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onFulfilled(this.value)
resolve(reason)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
})
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch (error) {
reject(error)
}
})
}
})
}
}
const promise = new HMPromise((resolve, reject) => {
reject(222)
})
promise.then(res => {
console.log('res1:' + res);
return 'aaa'
}, err => {
console.log('err1:'+err);
return 'bbb'
}).then((res) => {
console.log('res2:' + res);
},err => {
console.log('err2:' + err);
})
(2)Promise的catch和finally方法实现
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HMPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
});
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
onFulfilled = onFulfilled || (value => { return value })
return new HMPromise((resolve, reject) => {
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onFulfilled(this.value)
resolve(reason)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_PENDING) {
if(onFulfilled) {
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
})
}
if(onRejected) {
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch (error) {
reject(error)
}
})
}
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
}
const promise = new HMPromise((resolve, reject) => {
resolve(111)
})
promise.then(res => {
console.log('res1:' + res);
return 'aaa'
}).catch(err => {
console.log(err);
}).finally(() => {
console.log(123456);
})
实现resolv和reject方法
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HMPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
});
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
onFulfilled = onFulfilled || (value => { return value })
return new HMPromise((resolve, reject) => {
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onFulfilled(this.value)
resolve(reason)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_PENDING) {
if(onFulfilled) {
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
})
}
if(onRejected) {
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch (error) {
reject(error)
}
})
}
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new HMPromise((resolve) => {
resolve(value)
})
}
static reject(reason) {
return new HMPromise((resolve, reject) => {
reject(reason)
})
}
}
HMPromise.resolve('hallo world').then(res => {
console.log(res);
})
HMPromise.reject('Error').catch(err => {
console.log(err);
})
实现all和allSetted方法(node环境可能不支持)
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HMPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
});
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
onFulfilled = onFulfilled || (value => { return value })
return new HMPromise((resolve, reject) => {
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onFulfilled(this.value)
resolve(reason)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_PENDING) {
if(onFulfilled) {
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
})
}
if(onRejected) {
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch (error) {
reject(error)
}
})
}
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new HMPromise((resolve) => {
resolve(value)
})
}
static reject(reason) {
return new HMPromise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new HMPromise((resolve, reject) => {
const values = []
promises.forEach(promise => {
promise.then(res => {
values.push(res)
if(values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new HMPromise((resolve, reject) => {
const results = []
promises.forEach(promise => {
promise.then(res => {
results.push({ status: PROMISE_STATUS_FULFILLED, value:res})
if(results.length === promises.length) {
resolve(results)
}
}, err => {
results.push({ status: PROMISE_STATUS_REJECTED, value:err})
if(results.length === promises.length) {
resolve(results)
}
})
})
})
}
}
const p1 = new HMPromise(resolve => {
setTimeout(() => {
resolve(111)
}, 1000)
})
const p2 = new HMPromise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 2000)
})
const p3 = new HMPromise(resolve => {
setTimeout(() => {
resolve(333)
}, 3000)
})
HMPromise.allSettled([p1, p2, p3]).then(res => {
console.log(res);
})
实现race和any方法
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class HMPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if(this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
});
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
onFulfilled = onFulfilled || (value => { return value })
return new HMPromise((resolve, reject) => {
if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onFulfilled(this.value)
resolve(reason)
} catch (error) {
reject(error)
}
}
if(this.status === PROMISE_STATUS_PENDING) {
if(onFulfilled) {
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch (error) {
reject(error)
}
})
}
if(onRejected) {
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch (error) {
reject(error)
}
})
}
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new HMPromise((resolve) => {
resolve(value)
})
}
static reject(reason) {
return new HMPromise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new HMPromise((resolve, reject) => {
const values = []
promises.forEach(promise => {
promise.then(res => {
values.push(res)
if(values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new HMPromise((resolve, reject) => {
const results = []
promises.forEach(promise => {
promise.then(res => {
results.push({ status: PROMISE_STATUS_FULFILLED, value:res})
if(results.length === promises.length) {
resolve(results)
}
}, err => {
results.push({ status: PROMISE_STATUS_REJECTED, value:err})
if(results.length === promises.length) {
resolve(results)
}
})
})
})
}
static race(promises) {
return new HMPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reject(err)
})
})
})
}
static any(promises) {
const reasons = []
return new HMPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(resolve, err => {
reasons.push(err)
if(reasons.length === promises.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
}
const p1 = new HMPromise((resolve, reject) => {
setTimeout(() => {
reject(111)
}, 1000)
})
const p2 = new HMPromise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 2000)
})
const p3 = new HMPromise((resolve, reject) => {
setTimeout(() => {
reject(333)
}, 3000)
})
HMPromise.any([p1, p2, p3]).then(res => {
console.log(res);
}).catch(err => {
console.log(err.errors);
})