浅浅的了解Promise
上一篇同步和异步文章中说过js是单线程。js是用于页面交互,如果设计成多线程,一个线程对DOM进行添加操作,另一个线程同时对DOM进行删除操作,这样会让DOM很懵。单线程是为了避免操作DOM冲突。
Promise是ECMAScript6提供的类,为了更加优雅地书写复杂的异步任务。将callback回调方式从层层嵌套方式变成链式操作,使得代码更加清晰,同时更好的处理异步操作的成功与失败。
promise共有三种状态
pending 准备,fulfilled 成功,rejected失败
new Promise() 为pending 准备状态,状态还未确认。
fulfilled 准备状态转变成fulfilled,表示成功状态。一旦确认状态,就无法进行更改。
rejected 准备状态转变成rejected,表示失败状态。一旦确认状态,就无法进行更改。
Promise 的初步使用
Promise只有一个参数,并且这个参数是个函数。函数包含两个参数 resolve 和 reject,而这两个参数也都是个函数,resolve代表成功,reject代表拒绝(失败)。
第一步 new Promise
new Promise()调用了Promise的构造函数,且是立即执行。(上一篇同步和异步文章有介绍相关知识点)
例子:
new Promise((resolve,reject)=>{
console.log(1)
})
console.log(2)
输出结果: 先打印出1,再打印出2
第二步 .then
then方法就是处理状态。一个处理成功函数 一个处理失败函数,可以选择只处理成功或者失败,也可以两个状态一起写入进行处理。
完整写法:
new Promise((resolve,reject)=>{
//resolve()表示一种状态,成功状态。
resolve()
}).then(
//then用于处理状态,上面给出成功或者失败状态,进行处理。
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:成功
分析:程序执行到resolve()成功状态,走到then进行处理,因为状态是成功的,处理时走res(名称自己定义)函数,打印成功。如给出的状态是reject()拒绝状态,进入err函数,打印失败。所以then中输出的结果,取决于什么样的状态。
例子:
new Promise((resolve,reject)=>{
//reject()表示一种状态,拒绝(失败)状态。
reject()
}).then(
//then用于处理状态,上面给出成功或者失败状态,进行处理。
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:失败
分析:状态为reject失败状态,then就打印err函数结果,Promise中只有两种状态resolve成功和reject失败,两者选其一,then根据状态做出处理。
注:then()有两个参数也是函数,可以写一个参数。如果写一个参数,状态必须为resolve。也就是resolve成功参数必须有,reject参数可以不写。如果不写resolve成功参数,就用null代替。
写一个参数,reject失败状态下返回的结果
例子:
new Promise((resolve,reject)=>{
reject()
}).then(
value=>{
console.log(1)
}
)
输出结果: Uncaught (in promise) undefined
写一个参数,resolve成功状态下返回的结果
new Promise((resolve,reject)=>{
resolve()
}).then(
value=>{
console.log(1)
}
)
输出结果:1
用null占位,成功状态下。
new Promise((resolve,reject)=>{
resolve()
}).then(
null,
value=>{
console.log("失败")
}
)
输出结果:不报错
用null占位,失败状态下。
new Promise((resolve,reject)=>{
reject()
}).then(
null,
value=>{
console.log("失败")
}
)
输出结果:失败
then返回值
then返回的是一个Promise
例子:
let p1 = new Promise((res,err)=>{
res()
})
new Promise((res,err)=>{
console.log(p1)
}).then(
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:Promise {<fulfilled>: undefined}
return 的结果会返回给下一个then,下一个then是对Promise的返回处理
例子:
new Promise((res,err)=>{
res()
}).then(
res=>{
console.log("成功")
return '这个也成功了'
},
err=>{
console.log("失败")
}
).then(
res=>{
console.log(res)
},
err=>{
console.log(err)
}
)
输出结果:成功 这个也成功了
分析:then接收到成功状态进行处理,打印出成功,并将return的返回值传给下一个then,因为是成功状态所以打印出这个也成功了。
例子:
new Promise((res,err)=>{
res()
}).then(
res=>{
console.log("成功")
return new Promise((res,err)=>{})
},
err=>{
console.log("失败")
}
).then(
res=>{
console.log(1)
},
err=>{
console.log(2)
}
)
输出结果:成功
分析:then接收到成功状态进行处理,打印出成功,这里return是一个Promise,但是里面没有给出状态,所以第二个then没有等到状态通知,就不会加入微任务队列中,就不会打印出1。
例子:
new Promise((res,err)=>{
res()
}).then(
res=>{
console.log("成功")
return new Promise((res,err)=>{
err()
})
},
err=>{
console.log("失败")
}
).then(
res=>{
console.log(1)
},
err=>{
console.log(2)
}
)
输出结果:成功 2
分析:这里return是一个Promise,并且给出了状态,所以第二个then接收到拒绝状态通知,加入微任务队列中,打印出2。
接收的传值
例子:
new Promise((resolve,reject)=>{
reject("这是失败的")
}).then(
res=>{
console.log(res)
},
err=>{
console.log(err)
}
)
输出结果:这是失败的
分析:then接到的状态是拒绝状态,同时还有值。所以then打印的是reject中的值。
例子:
let data=[12,44,5]
new Promise((resolve,reject)=>{
resolve(data)
}).then(
res=>{
console.log(res)
},
err=>{
console.log("失败")
}
)
输出结果:数组:12, 44, 5
所以then中的内容可以自定义,也可以接收resolve和reject来传的值。
细节注意
例子:
new Promise((resolve,reject)=>{
console.log(1)
}).then(
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:1
分析:then没有获取到状态通知,就无法加入到微任务列队中。所以需要加上resolve()或reject(),告诉then状态,才会加入到微任务列队中。虽然不报错,但是程序也不会继续往下走,微任务里就没有这个任务。
Promise单一状态
resolve和reject只能有一种状态存在。
例子:
new Promise((resolve,reject)=>{
//成功状态
resolve()
//失败状态
reject()
}).then(
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:成功
例子:
new Promise((resolve,reject)=>{
//失败状态
reject()
//成功状态
resolve()
}).then(
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:失败
从这两个例子可以看出,两个状态下,最前面的状态起到作用,后面的状态将会是无效。因为程序进入时状态已经发出通知给then,then接到给出的状态,任务就已经加入到微队列中,无法进行改变。
所以Promise是单一的。状态一旦确定下来就不可改变的。
Promise状态中转
例子:
let p1=new Promise((resolve,reject)=>{
resolve("p1是成功的")
})
new Promise((resolve,reject)=>{
resolve(p1)
}).then(
res=>{
console.log("res:"+res)
},
err=>{
console.log("err:"+err)
}
)
输出结果:res:p1是成功的
分析:p1返回的是一个Promise,所以传入的就是p1的成功状态。
例子:
let p1=new Promise((resolve,reject)=>{
reject()
})
new Promise((resolve,reject)=>{
resolve(p1)
}).then(
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
输出结果:失败
分析:p1是失败状态, resolve(p1)接受的就是拒绝状态,then就走err。
.then() .catch() 和 .finally() 三个方法
Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列
.then()方法
then就是对状态的处理
new Promise((res,err)=>{
res()
}).then(
res=>{
console.log("成功")
},
err=>{
console.log("失败")
}
)
.catch()方法
catch是对异常进行处理,如果状态是失败情况下,then没有进行失败处理,可以通过catc处理。
例子:
new Promise((res,err)=>{
err()
}).then(
res=>{
console.log("成功")
}
)
输出结果:控制台报错
分析:失败状态,但是then中没有对失败状态进行处理函数。
例子:
new Promise((res,err)=>{
err()
}).then(
res=>{
console.log("成功")
}
).catch(err=>{
console.log("catch异常处理")
})
输出结果:catch异常处理
分析:catch里做了异常处理
catch建议放在最后一个then的后面,对前面的进行统一错误处理,防止遗漏。
.finally()方法
finally方法无论成功还是失败都会执行。
Promise静态方法
resolve() reject() all() race() 四个静态方法
应用场景:如果没有Promise实例,但是还想继续使用reject或resolve。就可以使用Promise.reject()或Promise.resolve()
resolve()成功方法
这里就是默认状态是成功,而不是准备阶段。
例子:
let p1 = Promise.resolve()
console.log(p1)
输出结果:Promise {<fulfilled>: undefined}
例子:
let p1 = Promise.resolve("成功")
p1.then(
res=>{
console.log(res)
}
)
输出结果:成功
reject()失败方法
这里就是默认状态是失败,而不是准备阶段。
例子:
let p1 = Promise.reject("失败")
p1.catch(
err=>{
console.log(err)
}
)
输出结果:失败
all()所有方法
例子:
let p1 = new Promise((resolve,reject)=>{
resolve(1)
})
let p2= new Promise((resolve,reject)=>{
resolve(2)
})
let p3 = new Promise((resolve,reject)=>{
resolve(3)
})
Promise.all([p1,p2,p3]).then(res=>{
console.log(res)
})
输出结果:1 2 3
分析:Promise.all([p1,p2,p3])中的所有Promise对象都执行结束后再执行。
例子:
let p1 = new Promise((resolve,reject)=>{
resolve(1)
})
let p2= new Promise((resolve,reject)=>{
reject(2)
})
let p3 = new Promise((resolve,reject)=>{
resolve(3)
})
Promise.all([p1,p2,p3]).then(res=>{
console.log(res)
},err=>{
console.log("失败"+err)
})
输出结果:失败2
分析:p2状态是失败的,就进入到err失败处理。p1,p2,p3中有一个失败就无法进入成功处理函数。
race()方法
只要一个完成,就代表都完成。先执行的第一个状态是成功,就进入成功函数,表示都成功了。如果先执行的第一是失败状态,就走异常函数处理。
例子:
let p1 = new Promise((resolve,reject)=>{
resolve(1)
})
let p2= new Promise((resolve,reject)=>{
reject(2)
})
let p3 = new Promise((resolve,reject)=>{
resolve(3)
})
Promise.race([p1,p2,p3]).then(res=>{
console.log(res)
},err=>{
console.log("失败"+err)
})
输出结果:1
例子:
let p1 = new Promise((resolve,reject)=>{
resolve(1)
})
let p2= new Promise((resolve,reject)=>{
reject(2)
})
let p3 = new Promise((resolve,reject)=>{
reject(3)
})
Promise.race([p1,p2,p3]).then(res=>{
console.log(res)
},err=>{
console.log("失败"+err)
})
输出结果:1
分析:先执行的第一个是p1,状态成功。进入then成功函数。
例子:
let p1 = new Promise((resolve,reject)=>{
setTimeout(function(){
resolve(1)
},1000)
})
let p2= new Promise((resolve,reject)=>{
reject(2)
})
let p3 = new Promise((resolve,reject)=>{
resolve(3)
})
Promise.race([p1,p2,p3]).then(res=>{
console.log(res)
},err=>{
console.log("失败"+err)
})
输出结果:失败2
分析:先执行的第一个是p2,失败状态。then走异常处理。
例子:
let p1 = new Promise((resolve,reject)=>{
setTimeout(function(){
resolve(1)
},1000)
})
let p2= new Promise((resolve,reject)=>{
setTimeout(function(){
resolve(1)
},2000)
})
let p3 = new Promise((resolve,reject)=>{
resolve(3)
})
Promise.race([p1,p2,p3]).then(res=>{
console.log(res)
},err=>{
console.log("失败"+err)
})
输出结果:3 分析:p1,p2都加入了定时器,最先执行的是p3,状态为成功。
根据最先执行的状态为准,应用于超时和记时的目的
Promise的优缺点
Promise优点
1.Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。
2.Promise 更适合处理一次性的结果。
3.链式处理是 Promise。
4.解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
5.更好的错误处理方式。
Promise缺点
1.一旦确认状态,无法中途取消。
2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3.当处于Pending状态时,无法得知目前进展到哪一个阶段。
4.Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。
本文章作为学习笔记,如有不对地方,请多多指正,谢谢.