前言
1、Promise是什么
1.1、理解
- 抽象表达:
- Promise是一门新的技术(ES6规范)
- Promise是JS中进行异步编程的新解决方案
备注:旧方案是单纯的使用回调函数
- 具体表达:
- 从语法上来说:Promise是一个构造函数
- 从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
1.2、promise的基本状态改变
- pending变为resolved
- pending变为rejected
说明:只有这两种,且
一个promise对象只能改变一次状态
。无论变为成功还是失败,都会有一个结果数据。
- 成功的结果数据一般称为value,失败的结果数据一般称为reason
1.3、promise的基本流程
2、为什么使用Promise
2.1、指定回调函数的方法更加灵活
- 旧的:必须再启动异步任务前指定
- promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以再异步任务结束后指定/多个)
2.2、支持链式调用,可以解决回调地狱问题
- 回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
- 回调地狱的缺点
- 不便于阅读
- 不便于一场处理
3、如何使用promise
如下-.-,查看API
API
1、构造函数
Promise构造函数:Promise (executor){}
- executor函数:执行器 {resolve, reject} => {}
- resolve函数:内部定义成功时我们调用的函数 value => {}
- reject函数:内部定义失败时我们调用的函数 reason => {}
说明:executor会在Promise内部立即同步调用,异步操作在执行器中执行
1.1、代码
<script>
let pms = new Promise((resolve,reject) => {
// 成功 promise的value为'aaa' 同步调用
resolve('aaa')
})
console.log(pms)
</script>
1.2、结果
2、Promise.prototype.then
Promise.prototype.then方法:(onResolved,onRejected) => {}
- onResolved函数:成功的回调函数 (value) => {}
- onRejected函数:失败的回调函数 (reason) => {}
说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调。返回一个新的Promise对象
2.1、代码
<script>
let pms1 = new Promise((resolve,reject) => {
// 成功 promise的value为'aaa'
resolve('aaa')
})
let pms2 = new Promise((resolve,reject) => {
// 失败 promise的value为'bbb'
reject('bbb')
})
let pms1Then = pms1.then(resolve => {
// pms1成功了,会走这个
console.log("pms1 resolve",resolve)
return resolve // return的值,作为pms2Then(promise对象)的result值。如果没有return,则默认undefined
},reject => {
console.log("pms1 reject",reject)
})
let pms2Then = pms2.then(resolve => {
console.log("pms2 resolve",resolve)
},reject => {
// pms2失败了,会走这个
console.log("pms2 reject",reject)
return reject // return的值,作为pms2Then(promise对象)的result值
})
console.log("pms1Then",pms1Then)
console.log("pms2Then",pms2Then)
</script>
2.2、结果
3、Promise.prototype.catch
Promise.prototype.catch方法:(onRejected) => {}
- onRejected函数:失败的回调函数 (reason) => {}
说明:它是
Promise.prototype.then(undefined, onRejected)
的快捷方式
3.1、代码
<script>
let pms1 = new Promise((resolve,reject) => {
// 成功 promise的value为'aaa'
resolve('aaa')
})
let pms2 = new Promise((resolve,reject) => {
// 失败 promise的value为'bbb'
reject('bbb')
})
let pms1Then = pms1.then(resolve => {
// pms1成功了,会走这个
console.log("pms1 resolve",resolve)
return resolve
},reject => {
console.log("pms1 reject",reject)
})
let pms2Catch = pms2.catch((reject => {
console.log("pm2 catch",reject)
return reject
}))
console.log("pms1Then",pms1Then)
console.log("pms2Catch",pms2Catch)
</script>
3.2、结果
4、Promise.prototype.finally
Promise.prototype.finally:() => {}
- 不管状态如何,都会执行的函数
4.1、代码
<script>
let pms1 = new Promise((resolve,reject) => {
// 成功 promise的value为'aaa'
resolve('aaa')
})
pms1.then(resolve => {
console.log(resolve)
// console.log("pms1回调方法执行完毕")
},reject => {
console.log(reject)
// console.log("pms1回调方法执行完毕")
})
pms1.finally(()=>{
console.log("pms1回调方法执行完毕")
})
</script>
4.2、结果
5、Promise.resolve
Promise.resolve方法:(value) => {}
- value:成功的数据或promise对象
- 如果参数是一个基本数据类型,则返回成功的promise对象,promise对象的值为传入的参数
- 如果参数是一个promise对象,则返回的promise对象的结果,是根据参数(promise对象)的结果来判断,如果参数promise对象成,则返回的promise对象的结果也是成功,反之失败。值也为参数promise对象返回的值
说明:返回一个成功/失败的promise对象
5.1、基本数据类型
5.1.1、代码
<script>
let pms = Promise.resolve('aaa')
console.log(pms)
</script>
5.1.2、结果
5.2、promise
5.2.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
resolve('我成功啦')
})
let p2 = new Promise((resolve,reject) => {
reject('我失败了')
})
let pms1 = Promise.resolve(p1)
let pms2 = Promise.resolve(p2)
console.log(pms1)
console.log(pms2)
</script>
5.2.2、结果
6、Promise.reject
Promise.reject方法:(reason) => {}
- reason:失败的原因
- 不管参数为基本数据类型还是promise对象,返回的promise对象始终为失败的
说明:返回一个失败的promise对象
6.1、基本数据类型与promise
6.1.1、代码
<script>
let p2 = new Promise((resolve,reject) => {
reject('我失败了')
})
let pms1 = Promise.reject('我成功啦')
let pms2 = Promise.reject(p2)
console.log(pms1)
console.log(pms2)
</script>
6.1.2、结果
7、Promise.all
Promise.all方法:(promises) => {}
- promises:包含n个promise的数组
- 返回的新的promise值为所有promise成功的值组成的数组,数组顺序与参数数组中promise的顺序一致
说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了,就直接失败,返回的结果为失败的promise的结果
7.1、全部成功
7.1.1、代码
<script>
let p1 = Promise.resolve('aaa')
let p2 = Promise.resolve('bbb')
let p3 = Promise.resolve('ccc')
let pms1 = Promise.all([p1,p2,p3])
console.log(pms1)
</script>
7.1.2、结果
7.2、有一个不成功
7.2.1、代码
<script>
let p1 = Promise.reject('aaa') // 失败
let p2 = Promise.resolve('bbb')
let p3 = Promise.resolve('ccc')
let pms1 = Promise.all([p1,p2,p3])
console.log(pms1)
</script>
7.2.2、结果
8、Promise.race
Promise.race方法:(promises) => {}
- promises:包含n个promise的数组
说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态
8.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
setTimeout(()=>{
resolve('aaa')
})
})
let p2 = new Promise((resolve,reject) => {
resolve('bbb')
})
let pms1 = Promise.race([p1,p2]);
console.log(pms1)
</script>
8.2、结果
Promise关键问题
1、如何改变promise的状态?
- resolve(value):如果当前时pending就会变为resolved
- reject(reason):如果当前时pending就会变为rejected
- 抛出异常:如果当前是pending就会变为rejected
1.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
resolve('aaa')
})
let p2 = new Promise((resolve,reject) => {
reject('bbb')
})
let p3 = new Promise((resolve,reject) => {
throw 'ccc';
})
console.log("p1",p1) // 成功
console.log("p2",p2) // 失败
console.log("p3",p3) // 失败
</script>
1.2、结果
2、一个promise指定多个成功/失败的回调函数,都会调用吗?
当promise改变为对应状态时都会调用
2.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
resolve('aaa')
})
p1.then((resolve) => {
console.log('aaa1:',resolve)
})
p1.then((resolve) => {
console.log('aaa2:',resolve)
})
</script>
2.2、结果
3、改变promise状态和指定回调函数谁先谁后?
- 都有可能,正常情况下实现指定回调再改变状态,但也可以先改变状态再指定回调
- 如何先改状态再指定回调?
- 再执行器中直接调用resolve()/reject()
- 延迟更长时间才调用then()
- 什么时候才能得到数据?
- 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
- 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
3.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
// 1.先改变状态
resolve('aaa')
})
p1.then(resolve => {
// 2.调用回调函数
})
// -----------------------------------------------------
let p2 = new Promise((resolve,reject) => {
// 2.然后改变状态
setTimeout(() => {
resolve('aaa')
},1000)
})
// 1.先指定回调
p2.then(resolve => {
// 3.状态改变后回调函数调用。
})
</script>
4、promise.then()返回的新的promise的结果状态由什么决定?
- 简单表达:由then()指定的回调函数执行的结果决定
- 详细表达:
- 如果抛出异常,新promise变为rejected,reason为抛出的异常
- 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值
- 如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
4.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
// 1.先改变状态
resolve('aaa')
})
// 非promise的任意值
let pThen1 = p1.then(value => {
return 'pThen1'
})
console.log("pThen1:",pThen1) // 成功
// 抛出异常
let pThen2 = p1.then(value => {
throw 'pThen2'
})
console.log("pThen2:",pThen2) // 失败
// 返回失败的promise
let pThen3 = p1.then(value => {
return new Promise((resolve,reject) => {
reject('pThen3')
})
})
console.log("pThen3:",pThen3) // 失败
</script>
4.2、结果
5、promise如何串联多个操作任务?
- promise的then()返回一个新的promise,可以看成then()的链式调用
- 通过then的链式调用串连多个同步/异步任务
5.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
// 1.等待1秒
setTimeout(()=>{
console.log('aaa')
resolve(true)
},1000)
})
p1.then(value => {
// 2.执行回调
return new Promise((resolve,reject) => {
// 3.等待1秒
setTimeout(()=>{
console.log('bbb')
resolve('ccc')
},1000)
})
}).then(value => {
// 4.成功的promise。执行回调
console.log(value) // ccc
})
</script>
5.2、结果
6、promise异常穿透?
- 当使用promise的then链式调用时,可以在最后指定失败的回调
- 前面任何操作出了异常,都会传到最后失败的回调中处理
6.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
setTimeout(()=>{
console.log('aaa')
// 链子地方任意一处失败,只需要在链子的最后面写一个catch即可获取到
reject(false)
},1000)
})
p1.then(value => {
return new Promise((resolve,reject) => {
console.log('bbb')
resolve('ccc')
})
}).then(value => {
console.log(value) // ccc
}).catch(reason => {
// 上面的链子中,不管哪个地方失败,都会走catch方法
console.error(reason)
})
</script>
6.2、结果
7、中断promise链?
- 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
- 办法:再回调函数中返回一个pendding状态的promise对象
7.1、代码
<script>
let p1 = new Promise((resolve,reject) => {
setTimeout(()=>{
console.log('aaa')
resolve(true)
},1000)
})
p1.then(value => {
// 想在这里执行完后,不走下面回调
console.log('bbb')
return new Promise((resolve,reject) => {
// 这个promise为pending状态
})
}).then(value => {
console.log('ccc')
}).catch(reason => {
console.error(reason)
})
</script>
7.2、结果
手写Promise
1、ES5 Function写法
1.1、初始化
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入手写Promise -->
<script src="./test1.js"></script>
</head>
<body>
<script>
let p = new Promise((resolve,reject) => {
resolve("OK")
})
p.then(value => {
console.log(value)
},reason => {
console.log(reason)
})
</script>
</body>
</html>
promise
function Promise(executor) {
function resolve(data){
}
function reject(data){
}
executor(resolve,reject);
}
Promise.prototype.then = function(onResolve,onReject){
}
2、封装resolve、reject
promise
function Promise(executor) {
// 初始状态为 pendding
this.PromiseState = 'pendding';
this.PromiseResult = null;
let that = this;
function resolve(data){
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled'
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
function reject(data){
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected'
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
executor(resolve,reject);
}
Promise.prototype.then = function(onResolve,onReject){
}
结果
3、封装throw后状态结果
抛出异常后,Promise会变为失败状态,失败后的值,就是throw的内容。
只需要把 executor try catch住即可
html里js
<script>
let p = new Promise((resolve,reject) => {
// reject("OK")
throw "error"
})
p.then(value => {
console.log(value)
},reason => {
console.log(reason)
})
console.log(p)
</script>
promise
function Promise(executor) {
this.PromiseState = 'pendding';
this.PromiseResult = null;
let that = this;
function resolve(data){
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
function reject(data){
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
// 抛出异常
try {
executor(resolve,reject);
}catch (e) {
// that.PromiseState = 'rejected';
// that.PromiseResult = e;
reject(e)
}
}
Promise.prototype.then = function(onResolve,onReject){
}
结果
4、promise状态只能修改一次
想要状态修改一次,我们只需要在修改状态前进行判断即可
html里js
<script>
let p = new Promise((resolve,reject) => {
resolve("ok") // 只走这一次
reject("error")
})
p.then(value => {
console.log(value)
},reason => {
console.log(reason)
})
console.log(p)
</script>
promise
function Promise(executor) {
this.PromiseState = 'pendding';
this.PromiseResult = null;
let that = this;
function resolve(data){
if (that.PromiseState === 'pendding'){
// 判断状态是否改变
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
}
function reject(data){
if (that.PromiseState === 'pendding') {
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
}
// 抛出异常
try {
executor(resolve,reject);
}catch (e) {
reject(e)
}
}
Promise.prototype.then = function(onResolve,onReject){
}
结果
5、then方法执行回调
执行回调,判断promise状态,执行相应的回调函数
promise
function Promise(executor) {
this.PromiseState = 'pendding';
this.PromiseResult = null;
let that = this;
function resolve(data){
if (that.PromiseState === 'pendding'){
// 判断状态是否改变
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
}
function reject(data){
if (that.PromiseState === 'pendding') {
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
}
}
// 抛出异常
try {
executor(resolve,reject);
}catch (e) {
reject(e)
}
}
Promise.prototype.then = function(onResolve,onReject){
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
onResolve(this.PromiseResult)
}else if(this.PromiseState === 'rejected'){
onReject(this.PromiseResult)
}
}
结果
6、异步任务回调执行
1.then回调函数异步
此时我们把引入的js文件注释掉,可以发现,then方法是异步任务,先打印的P,然后再执行then方法里的函数。我们这个是先执行then方法里的函数,然后才打印的p,在then方法里调用回调函数外面包一层setTimeout即可
2.executor函数异步
当executor函数为异步函数时,then回调函数要等executor执行完毕后,再执行。所以我们要在executor执行完毕后再调用then方法
html里js
<script>
let p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("ok")
},1000)
})
p.then(value => {
console.log(value)
},reason => {
console.log(reason)
})
console.log("p",p)
</script>
promise
function Promise(executor) {
this.PromiseState = 'pendding';
this.PromiseResult = null;
this.callBack = {};
let that = this;
function resolve(data){
if (that.PromiseState === 'pendding'){
// 判断状态是否改变
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
// 执行完毕后,调用then方法
if(that.callBack.res){
that.callBack.res(data)
}
}
}
function reject(data){
if (that.PromiseState === 'pendding') {
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
// 执行完毕后,调用then方法
if(that.callBack.rej){
that.callBack.rej(data)
}
}
}
// 抛出异常
try {
executor(resolve,reject);
}catch (e) {
reject(e)
}
}
Promise.prototype.then = function(onResolve,onReject){
setTimeout(() => {
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
onResolve(this.PromiseResult);
}else if(this.PromiseState === 'rejected'){
onReject(this.PromiseResult);
}else if(this.PromiseState === 'pendding'){
// 需要先把方法保存起来,才能在上面调用
this.callBack.res = onResolve;
this.callBack.rej = onReject;
}
})
}
结果
7、指定多个回调函数
当我们按照上面的代码写的时候,这时候当我们执行两个then方法,这时候只会走最后一个方法,因为最后一个方法在
then
方法里,把上面的方法替换掉了,所以只会走最后一个,这时候我们要把callBack变为数组,遍历以此执行
html里js
<script>
let p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("ok")
},1000)
})
p.then(value => {
console.log('111')
},reason => {
console.log(reason)
})
p.then(value => {
console.log('222')
},reason => {
console.log(reason)
})
console.log("p",p)
</script>
promise
function Promise(executor) {
this.PromiseState = 'pendding';
this.PromiseResult = null;
this.callBack = [];
let that = this;
function resolve(data){
if (that.PromiseState === 'pendding'){
// 判断状态是否改变
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
// 执行完毕后,调用then方法
that.callBack.forEach(item => {
item.res(data);
})
}
}
function reject(data){
if (that.PromiseState === 'pendding') {
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
// 执行完毕后,调用then方法
that.callBack.forEach(item => {
item.rej(data);
})
}
}
// 抛出异常
try {
executor(resolve,reject);
}catch (e) {
reject(e)
}
}
Promise.prototype.then = function(onResolve,onReject){
setTimeout(() => {
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
onResolve(this.PromiseResult);
}else if(this.PromiseState === 'rejected'){
onReject(this.PromiseResult);
}else if(this.PromiseState === 'pendding'){
// 需要先把方法保存起来,才能在上面调用
this.callBack.push({
res:onResolve,
rej:onReject
})
}
})
}
结果
8、同步修改状态then方法的返回结果
then方法要返回一个promise对象,
如果返回值为promise外其他类型,则为成功的promise,值为返回的值
如果返回值为promise类型,则根据这个promise的返回结果来改变返回值的返回结果
html里js
<script>
let p = new Promise((resolve,reject) => {
// setTimeout(() => {
resolve("ok")
// },1000)
})
let then1 = p.then(value => {
console.log('111')
// 返回的是undefined
},reason => {
console.log(reason)
})
let then2 = p.then(value => {
return new Promise((resolve,reject) => {
resolve('OOKK')
})
},reason => {
console.log(reason)
})
console.log("then1",then1)
console.log("then2",then2)
</script>
promise then方法
Promise.prototype.then = function(onResolve,onReject){
return new Promise((resolve,reject) => {
setTimeout(() => {
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
const resout = onResolve(this.PromiseResult);
if (resout instanceof Promise){
resout.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(resout);
}
}else if(this.PromiseState === 'rejected'){
const resout = onReject(this.PromiseResult);
if (resout instanceof Promise){
resout.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(resout);
}
}else if(this.PromiseState === 'pendding'){
// 需要先把方法保存起来,才能在上面调用
this.callBack.push({
res:onResolve,
rej:onReject
})
}
})
})
}
结果
9、异步修改状态then方法的返回结果
由于executor执行完毕后只会执行回调,并不会执行回调中promise中的resolve和reject方法,导致then方法返回的promise始终为
pendding
状态并且我们要判断then里面throw抛出异常后promise的状态
html里js
<script>
let p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("ok")
},1000)
})
let then1 = p.then(value => {
console.log(value)
// 返回的是undefined
},reason => {
console.log(reason)
})
let then2 = p.then(value => {
return 'OOKK'
},reason => {
console.log(reason)
})
let then3 = p.then(value => {
throw 'error'
},reason => {
console.log(reason)
})
console.log(then1)
console.log(then2)
console.log(then3)
</script>
promise then方法
Promise.prototype.then = function(onResolve,onReject){
return new Promise((resolve,reject) => {
setTimeout(() => {
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
try {
const result = onResolve(this.PromiseResult);
if (result instanceof Promise){
result.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(result);
}
}catch (e) {
reject(e);
}
}else if(this.PromiseState === 'rejected'){
try {
const result = onReject(this.PromiseResult);
if (result instanceof Promise){
result.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(result);
}
}catch (e) {
reject(e)
}
}else if(this.PromiseState === 'pendding'){
// 需要先把方法保存起来,才能在上面调用
this.callBack.push({
res: () => {
try {
// 获取then回调的返回值
let result = onResolve(this.PromiseResult)
if (result instanceof Promise){
result.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(result);
}
}catch (e) {
reject(e)
}
},
rej: () => {
try {
let result = onReject(this.PromiseResult)
if (result instanceof Promise){
result.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(result);
}
}catch (e) {
reject(e);
}
},
})
}
})
})
}
结果
10、then方法优化和完善
then方法里很多代码是重复代码,我们需要单独提取出来
promise
Promise.prototype.then = function(onResolve,onReject){
return new Promise((resolve,reject) => {
setTimeout(() => {
// 封装函数
const handleThen = (type) => {
try {
const result = type(this.PromiseResult);
if (result instanceof Promise){
result.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(result);
}
}catch (e) {
reject(e);
}
}
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
handleThen(onResolve);
}else if(this.PromiseState === 'rejected'){
handleThen(onReject);
}else if(this.PromiseState === 'pendding'){
// 需要先把方法保存起来,才能在上面调用
this.callBack.push({
res: () => {
handleThen(onResolve);
},
rej: () => {
handleThen(onReject);
},
})
}
})
})
}
结果
11、封装catch方法
html里js
<script>
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject("error")
},1000)
})
p.catch(e => {
console.log(e)
})
console.log(p)
</script>
promise catch方法
Promise.prototype.catch = function (onReject){
return this.then(undefined,onReject);
}
11、异常穿透与值传递
- 如果promise途中失败了,在then里面只写成功的回调方法,不写失败的,那么控制台就会报错,找不到onReject方法,我们要判断如果没有方法,就默认加一个
- 当我第一个then什么回调都没有写的时候,值会传递到第二个then中,并且顺利执行
html里js
<script>
let p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("error")
},1000)
})
p.then().then(value => {
console.log(value + '1')
}).then(value => {
console.log(value + '2')
}).catch(reason => {
console.log(reason + '3')
})
</script>
promise then方法
Promise.prototype.then = function(onResolve,onReject){
return new Promise((resolve,reject) => {
// 处理失败回调没有的情况
if (typeof onReject !== "function"){
// 往上抛,直到抛到catch
onReject = reason => {
throw reason
};
}
// 处理成功回调没有的情况
if(typeof onResolve !== "function"){
onResolve = value => {
return value
}
}
setTimeout(() => {
// 封装函数
const handleThen = (type) => {
try {
const result = type(this.PromiseResult);
if (result instanceof Promise){
result.then(value => {
resolve(value);
},reason => {
reject(reason);
})
}else {
resolve(result);
}
}catch (e) {
reject(e);
}
}
// 由于是p(promise)调用then方法,所以我们可以使用this
if(this.PromiseState === 'fulfilled'){
handleThen(onResolve);
}else if(this.PromiseState === 'rejected'){
handleThen(onReject);
}else if(this.PromiseState === 'pendding'){
// 需要先把方法保存起来,才能在上面调用
this.callBack.push({
res: () => {
handleThen(onResolve);
},
rej: () => {
handleThen(onReject);
},
})
}
})
})
}
结果
12、resolve静态方法封装
html里js
<script>
let p1 = Promise.resolve('111')
let p2 = Promise.resolve(new Promise((resolve,reject) => {resolve('OK')}))
let p3 = Promise.resolve(new Promise((resolve,reject) => {reject('ERROR')}))
let p4 = Promise.resolve(new Promise((resolve,reject) => {throw 'error'}))
console.log("p1",p1)
console.log("p2",p2)
console.log("p3",p3)
console.log("p4",p4)
</script>
promise resolve静态方法
Promise.resolve = function (data){
return new Promise((onResolve,onReject) => {
if (data instanceof Promise){
data.then(resolve => {
onResolve(resolve)
},reject => {
onReject(reject)
})
}else {
onResolve(data)
}
})
}
结果
13、reject静态方法封装
html里js
<script>
let p1 = Promise.reject('111')
let p2 = Promise.reject(new Promise((resolve,reject) => {resolve('OK')}))
let p3 = Promise.reject(new Promise((resolve,reject) => {reject('ERROR')}))
let p4 = Promise.reject(new Promise((resolve,reject) => {throw 'error'}))
console.log("p1",p1)
console.log("p2",p2)
console.log("p3",p3)
console.log("p4",p4)
</script>
promise reject静态方法
Promise.reject = function (data){
return new Promise((resolve,reject) => {
reject(data)
})
}
结果
14、all静态方法封装
html里js
<script>
let p1 = Promise.resolve('111')
let p2 = new Promise((resolve,reject) => {
resolve('OK2')
})
let p3 = new Promise((resolve,reject) => {
// reject('Error3')
resolve('OK3')
})
let all = Promise.all([p1,p2,p3,'aaa']);
console.log(all)
</script>
promise all静态方法
Promise.all = function (datas){
return new Promise((onResolve,onReject) => {
let resouts = []
let count = 0;
for (let i = 0; i < datas.length; i++) {
const data = datas[i];
debugger
if(data instanceof Promise){
data.then(resolve => {
resouts[i] = resolve;
count++;
if(count === datas.length){
onResolve(resouts)
}
},reject => {
onReject(reject)
})
}else {
resouts[i] = data
count++;
if(count === datas.length){
onResolve(resouts)
}
}
}
})
}
结果
全部成功
一个失败
15、race静态方法封装
html里js
<script>
let p1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('OK1')
})
})
let p2 = new Promise((resolve,reject) => {
resolve('OK2')
})
let all = Promise.race([p1,p2,'aaa']);
console.log(all)
</script>
promise race静态方法
Promise.race = function (datas){
return new Promise((onResolve,onReject) => {
for (let i = 0; i < datas.length; i++) {
let data = datas[i];
if(data instanceof Promise){
data.then(value => {
onResolve(value)
},reason => {
onReject(reason)
})
}else {
// 弥补then方法的异步时间
setTimeout(() => {
onResolve(data);
})
}
}
})
}
结果
2、ES6 Class写法
注意:静态方法前面要添加
static
关键字!!!
class Promise {
constructor(executor) {
this.PromiseState = 'pendding';
this.PromiseResult = null;
this.callBack = [];
let that = this;
function resolve(data){
if (that.PromiseState === 'pendding'){
// 判断状态是否改变
// 首先改变状态 PromiseState属性
that.PromiseState = 'fulfilled';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
// 执行完毕后,调用then方法
that.callBack.forEach(item => {
item.res(data);
})
}
}
function reject(data){
if (that.PromiseState === 'pendding') {
// 首先改变状态 PromiseState属性
that.PromiseState = 'rejected';
// 然后给结果赋值 PromiseResult属性
that.PromiseResult = data;
// 执行完毕后,调用then方法
that.callBack.forEach(item => {
item.rej(data);
})
}
}
// 抛出异常
try {
executor(resolve,reject);
}catch (e) {
reject(e)
}
}
then(onResolve,onReject) {
return new Promise((resolve, reject) => {
// 处理失败回调没有的情况
if (typeof onReject !== "function") {
// 往上抛,直到抛到catch
onReject = reason => {
throw reason
};
}
// 处理成功回调没有的情况
if (typeof onResolve !== "function") {
onResolve = value => {
return value
}
}
setTimeout(() => {
// 封装函数
const handleThen = (type) => {
try {
const result = type(this.PromiseResult);
if (result instanceof Promise) {
result.then(value => {
resolve(value);
}, reason => {
reject(reason);
})
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
// 由于是p(promise)调用then方法,所以我们可以使用this
if (this.PromiseState === 'fulfilled') {
handleThen(onResolve);
} else if (this.PromiseState === 'rejected') {
handleThen(onReject);
} else if (this.PromiseState === 'pendding') {
// 需要先把方法保存起来,才能在上面调用
this.callBack.push({
res: () => {
handleThen(onResolve);
},
rej: () => {
handleThen(onReject);
},
})
}
})
})
}
catch(onReject){
return this.then(undefined,onReject);
}
static resolve(data){
return new Promise((onResolve,onReject) => {
if (data instanceof Promise){
data.then(resolve => {
onResolve(resolve)
},reject => {
onReject(reject)
})
}else {
onResolve(data)
}
})
}
static reject(data){
return new Promise((resolve,reject) => {
reject(data)
})
}
static all(datas){
return new Promise((onResolve,onReject) => {
let resouts = []
let count = 0;
for (let i = 0; i < datas.length; i++) {
const data = datas[i];
debugger
if(data instanceof Promise){
data.then(resolve => {
resouts[i] = resolve;
count++;
if(count === datas.length){
onResolve(resouts)
}
},reject => {
onReject(reject)
})
}else {
resouts[i] = data
count++;
if(count === datas.length){
onResolve(resouts)
}
}
}
})
}
static race(datas){
return new Promise((onResolve,onReject) => {
for (let i = 0; i < datas.length; i++) {
let data = datas[i];
if(data instanceof Promise){
data.then(value => {
onResolve(value)
},reason => {
onReject(reason)
})
}else {
// 弥补then方法的异步时间
setTimeout(() => {
onResolve(data);
})
}
}
})
}
}
async与await
async
函数的返回值为promise对象
promise对象的结果由async函数执行的返回值决定
<script> async function test1(){ return 'aaa' } async function test2(){ return new Promise((resolve,reject) => { resolve("我成功啦") }) } console.log("test1",test1()) console.log("test2",test2()) </script>
await
await右侧的表达式一般为promise对象,但也可以是其它的值
如果表达式是promise对象,await返回的结果时promise成功的值
如果表达式是其它值,直接将此值作为await的返回值
<script> async function test1(){ let a = await 'aaa'; console.log("a",a); let b = await Promise.resolve('bbb') console.log("b",b) } test1() </script>
注意
await必须卸载async函数中,但async函数中可以没有await
如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
<script> /*function test1(){ 报错 await 'aaa'; }*/ async function test1(){ let a = ''; try { // 失败 p = new Promise((resolve,reject) => { reject('我失败了') }) // 抛出异常 a = await p; }catch (e){ a = '我真的失败了' } console.log(a) } test1() </script>
OK,Promise课程到此结束,欢迎下期再见~Bye