什么是Promise呢?
Promise是一个类,可以翻译成承诺 在通过new创建一个Promise对象时,我们需要传入一个回调函数,我们称之为executor
- 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve,reject;
- 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数
- 当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数
Promise使用过程,可以划分为三个状态:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝;
- 当执行executor中的代码时,处于该状态;
- 已兑现(fulfilled):意味着操作成功完成;
- 执行了resolve时,处于该状态;
- 已拒绝(rejected):意味着操作失败;
- 执行了reject时,处于该状态;
Executor
Executor是在创建Promise时需要传入的一个回调函数,这个回调函数会被立即执行,并且传入两个参数
new Promise((resolve, reject) => {
console.log("executor代码")
})
通常我们会在Executor中确定我们的Promise状态:
- 通过resolve 可以兑现(fulfilled)Promise的状态,我们也可以称之为已决议(resolved);
- 通过reject,可以拒绝(reject)Promise的状态;
在这里需要注意:一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的
- 在我们调用resole的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成兑现(fulfilled);
- 在之后我们去调用reject时,已经不会有任何的响应了(并不是这行代码不执行,而是无法改变Promise的状态);
resolve不同值的区别
- 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数;
- 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态
- 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态;
then/catch方法-多次调用
一个Promise的then/catch方法是可以被多次调用的
- 每次调用我们都可以传入对应的fulfilled或者rejected回调;
- 当Promise的状态变成fulfilled或rejected的时候,这些回调函数都会被执行;
promise.then(res =>{
console.log('处理1')
})
promise.then(res =>{
console.log('处理2')
})
promise.then(res =>{
console.log('处理3')
})
promise.catch(err =>{
console.log('处理1')
})
promise.catch(err =>{
console.log('处理2')
})
promise.catch(err =>{
console.log('处理3')
})
then方法-返回值
then方法本身是有返回值的,它的返回值是一个Promise,所以我们可以进行链式调用;
- 当then方法中的回调函数本身在执行的时候,那么它处于pending状态;
- 当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;
- 情况一:返回一个普通的值;
- 情况二:返回一个Promise;
- 情况三:返回一个thenable的值;
- 当then方法抛出一个异常时,那么它处于reject状态
catch方法-返回值
catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法:
promise.catch(err => {
console.log(1)
}).catch(err => {
console.log(2)
}).then(res => {
console.log(3)
})
//如果promise最初状态是fulfilled,输出结果: 1 3 因为catch传入的回调在执行完后,默认状态依然会是fulfilled的
//如果我们希望后续继续执行catch,那么需要抛出一个异常
promise.catch(err => {
console.log(1)
throw new Error('error message')
}).catch(err => {
console.log(2)
}).then(res => {
console.log(3)
})
//如果promise最初状态是fulfilled,输出结果 1 2 3
finally方法
finally是在ES9中新增的一个特性:finally方法不接收参数,它表示无论promise状态如何,最终都会执行的代码.
promise.then(res => {
console.log(1)
}).catch(err => {
console.log(2)
}).finally(() => {
console.log(3)
})
//如果promise最初状态是fulfilled,输出结果 1 3
resolve类方法
我们可以使用Promise.resolve将现成内容转成Promise resolve参数形态:
- 参数是一个普通的值或者对象
- 参数本身是个Promise
- 参数是一个thenable
Promise.resolve("luo")
// 等价于
new Promise((resolve)=>resolve("luo"))
reject类方法
我们可以使用Promise.reject将现成内容转成Promise的rejected状态 Promise.reject传入的参数无论是什么形态,都会直接作为reject状态的参数传递到catch的
Promise.reject("luo")
// 等价于
new Promise((resolve,reject)=>reject("luo"))
all类方法
它将多个Promise包裹在一起形成一个新的Promise; 新Promise状态由包裹的所有Promise共同决定:
- 当所有的Promise状态为fulfilled时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;
- 当又一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;
let p1 = Promise.resolve("luo1")
let p2 = Promise.resolve("luo2")
let p3 = Promise.reject("luo3")
Promise.all([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
//输出 luo3
allSettled方法
- all方法有一个缺陷:当有其中一个Promise变成reject时,新Promise就会立即变成对应的reject状态.
- 那么对于已经resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的; 在ES11中,添加了新的API Promise.allSettled
- 该方法会在所有Promise都有结果(settled),无论fulfilled还是reject 才会有最终的状态;并且这个Promise的结果一定是fulfilled的
let p1 = Promise.resolve("luo1")
let p2 = Promise.resolve("luo2")
let p3 = Promise.reject("luo3")
Promise.allSettled([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
race方法
如果一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法;
- race是竞赛的意思,表示多个Promise 谁先有结果,那么就使用谁的结果;
let p1 = Promise.resolve("luo1")
let p2 = Promise.resolve("luo2")
let p3 = Promise.reject("luo3")
Promise.race([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
// 输出 luo1
any方法
any方法是ES12中新增的方法,和race方法是类似的:
- any方法会等到一个fulfilled状态,才会决定新Promise的状态;
- 如果所有Promise都是reject的,那么也会等到所有Promise都变成rejected状态;并且会报一个AggregateError的错误.
let p1 = Promise.resolve("luo1")
let p2 = Promise.resolve("luo2")
let p3 = Promise.reject("luo3")
Promise.any([p1, p2, p3]).then(res => {
console.log('1',res)
}).catch(err => {
console.log('2',err)
})
手写Promise
myPromise constructor实现
const PROMISE_STATUS_PENDING = "pending"
const PROMISE_STATUS_FULFILLED = "fulfilled"
const PROMISE_STATUS_REJECTED = "rejected"
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
console.log("resolve")
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
console.log("reject")
}
}
executor(resolve, reject)
}
}
const promise = new myPromise((resolve, reject) => {
console.log("立即执行")
resolve("111")
reject("222")
})
myPromise then基础版本实现
const PROMISE_STATUS_PENDING = "pending"
const PROMISE_STATUS_FULFILLED = "fulfilled"
const PROMISE_STATUS_REJECTED = "rejected"
function execFunctionWithCatchError(execFn, value, resolve, reject){
try{
const result = execFn(value) //判断result是不是一个promise或者thenable 如果是应该由result决定promise状态
resolve(result)
}catch(err){
reject(err)
}
}
class myPromise {
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 (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
return new myPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled){
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected){
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_STATUS_PENDING){
//将成功和失败的回调收集到数组中
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
}
const promise = new myPromise((resolve, reject) => {
console.log("立即执行")
// resolve("111")
// reject("222")
throw new Error('error')
})
promise.then((res) => {
console.log("res1", res)
return 333
}, (err) => {
console.log("err1", err)
throw new Error('444')
}).then((res) => {
console.log("res2", res)
}, (err) => {
console.log("err2", err)
})
setTimeout(() => {
promise.then((res) => {
//console.log("res4", res)
})
}, 1000);
myPromise catch/finally 实现
const PROMISE_STATUS_PENDING = "pending"
const PROMISE_STATUS_FULFILLED = "fulfilled"
const PROMISE_STATUS_REJECTED = "rejected"
function execFunctionWithCatchError(execFn, value, resolve, reject){
try{
const result = execFn(value) //这边还要判断result是不是一个promise或者thenable 如果是应该由result决定promise状态
resolve(result)
}catch(err){
reject(err)
}
}
class myPromise {
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) {
//添加微任务推迟执行 因为执行resolve或者reject的时候.then方法都还没执行 获取不到传进来的函数
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 (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
/*解决.then不写第二个err函数 直接写.catch
导致onRejected是undefined没有被成功收集到onRejectedFns数组里
我们应该在第一个then没处理的时候 移交给下一个catch或者有err函数的then*/
onRejected = onRejected || (err => { throw err })
/* 同样是解决promise先写.catch后 它之后的.then或者是.finally
因为onFulfilled是undefined没有被成功收集到onFulfilledFns数组里
没有成功执行自然也没有返回一个myPromise 无法后续调用*/
onFulfilled = onFulfilled || (value => { return value })
//这里返回一个myPromise 解决链式调用的问题
return new myPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED){
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED){
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_STATUS_PENDING){
//将成功和失败的回调收集到数组中
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected){
return this.then(undefined,onRejected)
}
finally(onFinally){
this.then(onFinally,onFinally)
}
}
const promise = new myPromise((resolve, reject) => {
console.log("立即执行")
resolve("111")
})
promise.then((res) => {
console.log("res1", res)
return '222'
}).then((res) => {
console.log("res2", res)
}).catch(err=>{
console.log('catch',err);
}).finally((f)=>{
console.log('finally',f);
})
myPromise 类方法的实现
const PROMISE_STATUS_PENDING = "pending"
const PROMISE_STATUS_FULFILLED = "fulfilled"
const PROMISE_STATUS_REJECTED = "rejected"
function execFunctionWithCatchError(execFn, value, resolve, reject){
try{
const result = execFn(value) //这边还要判断result是不是一个promise或者thenable 如果是应该由result决定promise状态
resolve(result)
}catch(err){
reject(err)
}
}
class myPromise {
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) {
//添加微任务推迟执行 因为执行resolve或者reject的时候.then方法都还没执行 获取不到传进来的函数
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 (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
/*解决.then不写第二个err函数 直接写.catch
导致onRejected是undefined没有被成功收集到onRejectedFns数组里
我们应该在第一个then没处理的时候 移交给下一个catch或者有err函数的then*/
onRejected = onRejected || (err => { throw err })
/* 同样是解决promise先写.catch后 它之后的.then或者是.finally
因为onFulfilled是undefined没有被成功收集到onFulfilledFns数组里
没有成功执行自然也没有返回一个myPromise 无法后续调用*/
onFulfilled = onFulfilled || (value => { return value })
//这里返回一个myPromise 解决链式调用的问题
return new myPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED&&onFulfilled){
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED&&onRejected){
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
if(this.status === PROMISE_STATUS_PENDING){
//将成功和失败的回调收集到数组中
if(onFulfilled)this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
if(onRejected)this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected){
return this.then(undefined,onRejected)
}
finally(onFinally){
return this.then(onFinally,onFinally)
}
static resolve(value){
if(typeof(value)==='object'&&typeof(value.then)==='function'&&typeof(value.catch)==='function'){
return value
}
return new myPromise((resolve)=>resolve(value))
}
static reject(reason){
if(typeof(reason)==='object'&&typeof(reason.then)==='function'&&typeof(reason.catch)==='function'){
return reason
}
return new myPromise((resolve,reject)=>reject(reason))
}
static all(promises){
return new myPromise((resolve,reject)=>{
let value = []
promises.forEach(promise =>{
myPromise.resolve(promise).then(res=>{
value.push(res)
if(promises.length === value.length){
resolve(value)
}
},err=>{
reject(err)
})
})
})
}
static allSettled(promises){
return new myPromise((resolve,reject) => {
let value = []
promises.forEach(promise => {
myPromise.resolve(promise).then(res=>{
value.push({
status:'fulfilled',
value:res
})
if(promises.length === value.length){
resolve(value)
}
},err=>{
value.push({
status:'rejected',
reason:err
})
if(promises.length === value.length){
resolve(value)
}
})
})
})
}
static race(promises){
return new myPromise((resolve,reject)=>{
promises.forEach(promise =>{
myPromise.resolve(promise).then(res=>{
resolve(res)
},err=>{
resolve(err)
})
})
})
}
static any(promises){
return new myPromise((resolve,reject)=>{
let reason = []
promises.forEach(promise=>{
myPromise.resolve(promise).then(res=>{
resolve(res)
},err=>{
reason.push(err)
if(reason.length === promises.length){
reject(new AggregateError(reason))
}
})
})
})
}
static retry(fn,times){
return new myPromise(async (resolve, reject) => {
let i = 1
while (times--){
try{
const res = await fn()
resolve(res)
break
}catch(error){
console.log(`第${i++}次失败`,error);
if(!times){
reject(error)
}
}
}
})
}
}
function fn(){
const n = Math.random();
return new myPromise((resolve, reject) => {
setTimeout(() => {
if(n>0.7){
resolve(n)
}else{
reject(n)
}
}, 1000);
})
}
myPromise.retry(fn,3).then(res=>{
console.log('成功',res);
return 111
}).catch(err=>{
console.log('3次失败');
return 222
}).finally(res=>{
console.log('finally',res);
})
myPromise.all(['1','2',promise]).then(res=>{
console.log('all res',res);
}).catch(err=>{
console.log('all err',err);
})
myPromise.allSettled(['1','2',promise]).then(res=>{
console.log('allSettled res',res);
}).catch(err=>{
console.log('allSettled err',err);
})
myPromise.race([promise,'1','2']).then(res=>{
console.log('race res',res);
}).catch(err=>{
console.log('race err',err);
})
myPromise.any([promise,promise,promise]).then(res=>{
console.log('any res',res);
}).catch(err=>{
console.log('any err',err);
})