简单实现
- 1.新建MyPromise类,传入执行器executor
- 2.executor传入resolve和reject方法
- 3.状态与结果的管理
- 4.then简单实现
- 5.使用module.exports对外暴露MyPromise类
在promise类中加入异步逻辑
- 缓存成功与失败回调
- then方法中的Pending的处理
- resolve与reject中调用回调函数
实现then方法多次调用添加多个处理函数
Promise的then方法是可以被多次调用的。如果有多个then的调用,如果是同步回调,直接返回当前的值。如果是异步回调,那么保存的成功失败的回调,需要用不同的值保存,因为都互不相同。
- MyPromise类中新增两个数组
- 回调函数存入数组中
- 循环调用成功和失败回调
实现then方法的链式调用
then方法要链式调用那么就需要返回一个Promise对象 then方法里面return一个返回值作为下一个then方法的参数,如果是return一个Promise对象,就需要判断它的状态
then方法链式调用识别Promise是否返回自己
如果then方法返回的是自己的Promise对象,则会发生循环调用,这个是否程序会报错
再次修改
捕捉错误
- then执行时错误捕获
promise.js
// 自定义Promise函数模块: IIFE
(function(window){
/*
Promise构造函数
excutor:执行器函数(同步执行)
*/
function Promise(excutor){
// 属性
const _this = this //将当前promise对象保存起来
_this.status = 'pending'//给promise对象指定status属性,初始值为pending
_this.data = undefined //给promise对象指定一个用于存储结果数据的属性
_this.callbacks = [] // 每个元素的结构:{onResolved(){},onRejected(){}}
//resolve方法
function resolve(value){
if(_this.status !== 'pending'){ //如果当前状态不是pending,直接结束
return
}
_this.status = 'resolved' //将状态改为resolved
_this.data= value //保存value 数据
if(_this.callbacks.length > 0){//如果有待执行callback函数,立即异步执行回调函数onResolved
setTimeout(() => {
_this.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
})
})
}
}
// reject方法
function reject(reason){
if(_this.status !== 'pending'){//如果当前状态不是pending,直接结束
return
}
_this.status = 'rejected'//将状态改为rejected
_this.data= reason//保存value 数据
if(_this.callbacks.length > 0){//如果有待执行callback函数,立即异步执行回调函数onRejected
setTimeout(() => {
_this.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
})
}}
//立即同步执行executor
try{
excutor(resolve,reject)
}catch(error){//如果执行器跑出异常,promise对象变为rejected状态
reject(error)
}
}
/*
Promise原型对象的then()
指定成功和失败的回调函数
返回一个新的promise对象
*/
Promise.prototype.then = function(onResolved,onRejected){
const _this = this
// 返回一个新的promise对象
return new Promise((resolve,reject)=>{
if(_this.status === 'pending'){
//假设当前状态是pending,
_this.callbacks.push({
onResolved,
onRejected
})
}else if(_this.status ==='resolved'){
setTimeout(()=> {
/*
1:如果跑出异常,return的promise就会失败,reason就是error
2:如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
3:如果回调函数返回是promise,return的promise的结果就是这个promise的结果
*/
try {
const result = onResolved(_this.data)
if(result instanceof Promise){
result.then(
value =>resolve(value), //当result成功时,让return的promise也成功
reason => reject()//当result失败时,让return的promise失败
)
} else {
resolve(result)
} catch (error){
reject(error)
}
}
})
}else {
setTimeout(()=> {
onRejected(_this.data)
})
}
})
}
/*
Promise原型对象的catch()
指定失败的回调函数
返回一个新的promise对象
*/
Promise.prototype.catch = function (onRejected){
}
/*
Promise函数对象的resolve方法
返回一个指定结果的成功的promise
*/
Promise.resolve = function (value){
}
/*
Promise函数对象的reject方法
返回一个指定reason的失败的promise
*/
Promise.reject = function (reason){
}
/*
Promise函数对象的all方法
返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就返回失败
*/
Promise.all = function (promises){
}
/*
Promise函数对象的race方法
返回一个promise,其结果有第一个完成的promise决定
*/
Promise.race = function (promises){
}
//向外暴露Promise函数
window.Promise = Promise
})(window)
// html
<script src="./promise.js">
<script>
const p = new Promise((resolve,reject) => {
setTimeout(()=> {
resolve(1)
},1000)
})
p.then(
value =>{
console.log('onResolved1()',value)
},
reason => {
console.log('onRejected()',reason)
}
)
</script>
Promise基础面试题
Promise状态改变后,promise.then才会执行
const promise = new Promise((resolve,reject)=>{
console.log('1')
});
promise.then(()=>{
console.log('2')
})
console.log('3')
结果:
1 3
- new Promise()是否包裹在函数当中
const fn =() =>(new Promise((resolve,reject) =>{
console.log('1')
resolve('success')
}))
fn().then(res =>{
console.log(res)
})
console.log('start')
解析:fn函数是直接返回一个new Promise的,而且fn函数的调用时在start之前,所以它里面的内容应该会先执行 结果:
1 start success
- 如果把fn的调用放在start之后
const fn =() =>
new Promise((resolve,reject) =>{
console.log('1')
resolve('success')
})
console.log('start')
fn().then(res =>{
console.log(res)
})
解析:new Promise()是包裹在函数当中的,只有在函数调用的时候才会执行 结果:
start 1 success
Promise结合setTimeout
const promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('success')
},1000)
})
const promise2 = promise1.then(()=>{
throw new Error('error')
})
console.log('promise1',promise1)
console.log('promise2',promise2)
setTimeout(()=>{
console.log('promise1',promise1)
console.log('promise2',promise2)
},2000)
结果:
'promise1' Promise{ <pending> }
'promise2' Promise{<pending>}
'promise1' Promise{<resolved>:'success'}
'promise2' Promise{<rejected>:Error:error!!!}
解析:关键步骤: 先执行第一个定时器里的内容,将promise1的状态改为resolved且保存结果并将之前的promise1.then推入微任务队列
该定时器中没有其它的同步代码可执行,因此执行本轮的微任务队列,也就是promise1.then,它抛出了一个错误,且将promise2的状态设置为rejected
Promise中的then、catch、finally
总结:
- 1:Promise的状态一经改变就不能再改变
const promise = new Promise((resolve,reject)=>{
resplve('success1')
reject('error')
resolve('success2')
})
promise.then(res=>{
console.log('then',res)
}).catch(err =>{
console.log('catch',err)
})
// 结果
then success1
构造函数中的resolve或reject只有第一次执行有效,多次调用没有任何作用。
- 2:.then和.catch都会返回一个新的Promise
- 3:catch不管被连接到哪里,都能捕获上层未捕捉过的错误。
catch()也会返回一个promise,由于这个promise没有返回值,所以是undefined
const promise = new Promise((resolve,reject)=>{
reject('error')
resolve('success1')
})
promise.then(res =>{
console.log('then1',res)
}).then(res => {
console.log('then2',res)
}).catch(err=>{
console.log('catch',err)
}).then(res=>{
console.log('then3',res)
})
// 结果
catch, error
then3,undefined
解析:
1:catch不管被连接到哪里,都能捕获上层未捕捉过的错误
2:catch()也会返回一个promise,由于这个promise没有返回值,所以是undefined
- 4:在promise中,返回任意一个非Promise的值都会被包裹成promise对象
- 5:Promise的.then或者.catch可以被调用多次,但如果Promise内部的状态一经改变,并且有了一个值,那么后续每次调用.then或者.catch的时候都会直接拿到该值。
Promise.resolve(1)
.then(res => {
console.log(res)
return 2 // resolve(2)
})
.catch(err =>{
return 3
})
.then(res =>{
console.log(res)
})
// 结果;1 2
解析:
Promise可以链式调用,不过promise每次调用.then或.catch都会返回一个新的promise,从而实现了链式调用。
- 6:.then或者.catch中return一个error对象并不会抛出错误,所以不会被后续的.catch捕获
Promise.resolve().then(()=>{
return new Error('error')
}).then(res =>{
console.log('then',res)
}).catch(err=>{
console.log('catch',err)
})
// 结果:then,Error:error
解析:返回任意一个非promise的值都会被包裹成promise对象
return new Error('error')会被包裹成return Promise.resolve(new Error('error'))
- 7:.then或.catch返回的值不能是promise本身,否则会造成死循环
const promise = Promise.resolve().then(()=>{
return promise
})
promise.catch(console.err)
// 结果:报错,出现死循环
- 8:.then或者.catch的参数期望是函数,传入非函数则会发生值透传
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
//结果:1
解析:.then或.catch的参数期望是函数,传入非函数则会发生值透传
- 9:.then方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,再某些时候可以认为catch是.then第二个参数的简便写法
Promise.reject('err!!!')
.then((res)=>{
console.log('success',res)
},(err)=>{
console.log('error',err)
}).catch(err=>{
console.log('catch',err)
})
//结果:'error' 'error!!!'
// 解析:
.then函数中的两个参数,第一个参数是用来处理Promise成功的函数。第二个是处理失败的函数。
Promise.resolve('1')的值会进入成功的函数
Promise.reject('2')会进入失败的函数
- 10:.finally方法也是返回一个Promise,它在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数。
Promise中的all和race
- .all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调
- .race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他方法仍在执行,不过执行结果会被抛弃