文章目录
1、promise简介
定义:promise是es6引入的一种新的解决异步编程的方案。从语法上来说,是一个构造函数,可以实例化对象,封装异步操作,获取成功或失败的结果,其优点是支持链式调用,可以解决回调问题;指定回调的方式更为灵活。
2、promise初体验
2.1 题目:设计一个抽奖,中奖的概率为30%
1):用常规方式实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>promise初体验</title>
</head>
<body>
<button>点我抽奖</button>
</body>
<script>
// 获取随机整数[min,max]
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var btn = document.querySelector("button");
btn.onclick = function () {
setTimeout(() => {
var n = getRandom(1, 100);
if (n <= 30) {
alert("恭喜您,获得一台全新iPhone15!");
} else {
alert("很遗憾,奖品与您擦肩而过,再接再厉!");
}
}, 3000);
};
</script>
</html>
2)promise实现:promise对象可以包裹一个异步操作,成功时调用resolve()方法,失败时调用reject方法,通过promise的then方法执行回调(第一个函数为成功时的回调,第二个为失败时的回调)
<script>
// 获取随机整数[min,max]
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var btn = document.querySelector("button");
btn.onclick = function () {
// setTimeout(() => {
// var n = getRandom(1, 100);
// if (n <= 30) {
// alert("恭喜您,获得一台全新iPhone15!");
// } else {
// alert("很遗憾,奖品与您擦肩而过,再接再厉!");
// }
// }, 3000);
var p = new Promise((resolve,reject)=>{
setTimeout(() => {
var n = getRandom(1, 100);
if (n <= 30) {
resolve() //将promise对象的状态设置为[success]
} else {
reject() //将promise对象的状态设置为[fail]
}
}, 3000);
})
// 调用then方法
p.then(()=>{
alert("恭喜您,获得一台全新iPhone15!");
},()=>{
alert("很遗憾,奖品与您擦肩而过,再接再厉!");
})
};
</script>
2.2 题目:封装一个函数sendAjax发送GET AJAX请求;参数URL;返回结果Promise对象
ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>promise初体验</title>
</head>
<body>
<button>发送sendAjax请求</button>
</body>
<script>
// 封装一个sendAjax函数
function sendAajx(url){
return new Promise((resolve,reject)=>{
var xhr = new XMLHttpRequest()
// xhr.responseType = 'json'
xhr.open('GET',url)
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status>=200&&xhr.status<300){
resolve(xhr.response)
}else{
reject(xhr.status)
}
}
}
})
}
var btn = document.querySelector("button");
btn.onclick = function () {
sendAajx('http://127.0.0.1:8000/ajax').then(
(res)=>{
console.log(res)
},(code)=>{
console.log('失败:'+code)
})
};
</script>
</html>
server.js
const express = require('express')
var app = new express()
app.get('/ajax',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
response.send("用户数据")
})
app.listen(8000,()=>{
console.log('8000端口正在运行中....')
})
控制台打印结果:
3、promise的状态
-
promise的一个属性 [PromiseState]
- pending 未决定的
- resolved/fullfilled 成功的
- rejected 失败的
-
promise状态的改变
- pending–>resolved/fullfilled
- pending–>rejected
const p=new Promise((resolve,reject)=>{})
4、promise对象的值
属性值 [PromiseResult],保存着异步任务成功或者失败后的结果,可以通过resolve和reject两个函数进行修改,即resolve或者reject的形参值
5、promise的工作流程
6、promise的相关API
(1)Promise构造函数:Promise(excutor){}
- executor函数:执行器(resolve,reject)=> { }
- resolve函数:内部定义成功时调用的函数:value => {}
- reject函数:内部定义失败时调用的函数:reason=> {}
注意:excutor会在Promise内部立即同步调用,异步操作在执行器中执行
(2)Promise.prototype.then(onResolved,onRejected)
- onResolved:成功的回调函数
- onRejected:失败的回调函数
- 最终返回一个新的Promise对象
(3) Promise.prototype.catch(onRejected)
-
onRejected:失败的回调函数
以下是promise函数对象中的方法,而非实例对象
(4)promise.resolve()方法:(value)=>{}
- value:成功的数据或promise对象
- 说明:返回一个成功或失败的promise对象
- ①如果resolve传入的是一个非promise的值,返回值为成功的promise,其结果为该值,②如果传入的是一个promise对象,返回值成功或失败根据传入的promise决定,结果为传入的promise结果
let p1=Promise.resolve(520)
console.log(p1);
let p2=Promise.resolve(new Promise((resolve,reject)=>{
resolve("ok")
}))
console.log(p2);
let p3=Promise.resolve(new Promise((resolve,reject)=>{
reject("err")
}))
console.log(p3);
(5)promise.reject()方法:(reason)=>{}
- 说明:返回一个失败的promise对象(状态为rejected),传入什么,失败的结果就是什么,假如传入的是一个成功的promise对象,那么结果就是那个成功的promise对象
const p4=Promise.reject(new Promise((resolve,reject)=>{
resolve("ok")
}))
console.log(p4);
(6)promise.all方法:[promise]=>{}
- promise:包含n个promise数组
- 说明:返回一个新的promise,只有所有promise都成功才成功,只要有一个失败都失败。如果成功,结果值为他们分别成功的结果组成的数组,如果失败,结果值为失败的那个promise的结果
let p1=new Promise((resolve)=>{
resolve("ok")
})
let p2=new Promise((resolve)=>{
resolve("success")
})
const p=Promise.all([p1,p2])
console.log(p);
let p1=new Promise((resolve)=>{
resolve("ok")
})
let p2=new Promise((resolve)=>{
resolve("success")
})
let p3=new Promise((resolve,reject)=>{
reject("err")
})
const p=Promise.all([p1,p2,p3])
console.log(p);
(7) promise.race()方法:[promise]=>{}
- promise:包含n个promise数组
- 返回一个新的promise,第一个改变状态的promise为最终结果
let p1=new Promise((resolve)=>{
setTimeout(()=>{
resolve("ok")
},1000)
})
let p2=new Promise((resolve)=>{
resolve("success")
})
let p3=new Promise((resolve,reject)=>{
reject("err")
})
const p=Promise.race([p1,p2,p3])
console.log(p);
7、promise的几个关键问题
7.1 Promise对象状态改变的方式
- resolve函数
- reject函数
- throw抛出错误
相关代码:
<script>
let p = new Promise((resolve,reject)=>{
// 1、resolve函数
resolve('ok') //pending => fullfiled(resolved)
// 2、reject函数
reject('error') // pending => rejected
// 3、抛出错误
throw '出问题了'
})
console.log(p)
</script>
打印结果分别为:
resolve():
reject():
throw:
7.2 promise执行多个回调
当promise改变为对应状态时都会执行
相关代码:
<script>
let p = new Promise((resolve,reject)=>{
resolve()
})
p.then(()=>{
console.log('one');
})
p.then(()=>{
console.log('two');
})
</script>
打印结果:
7.3 改变promise状态和指定回调谁先执行
1)都有可能,正常情况下,先指定回调,再改变状态,但也可以先改变状态再执行回调
2)如何先改变状态再指定回调?
① 在执行器中直接调用resolve()/reject
② 延长更长时间再调用then
3)什么时候才能得到数据?
① 如果先指定的回调,当状态改变时,回调函数就会调用,执行回调,得到数据
②如果先改变状态,当指定回调时,回调函数就会调用,得到数据
7.4 promise.then方法的返回结果特点
- 非promise,返回promise状态为成功,结果为返回的结果
- 为promise对象,返回的结果为promise的结果
- 抛出错误
相关代码:
<script>
let p = new Promise((resolve,reject)=>{
resolve()
})
let result = p.then(()=>{
// 1.非promise,返回promise状态为成功,结果为返回的结果
// return 'ok'
// 2.为promise对象,返回的结果为promise的结果、
// return new promise((resolve,reject)=>{
// reject('error')
// })
// 3.抛出错误
throw '出了问题'
},()=>{
})
console.log(result)
</script>
对于上述代码的打印结果分别如下:
7.5 如何串联多个任务
练习代码:
<script>
var p = new Promise((resolve,reject)=>{
resolve('success')
})
p.then((val)=>{
console.log(val)
return 'ok'
}).then((val)=>{
console.log(val);
return new Promise((resolve,reject)=>{
resolve('yes')
})
}).then((val)=>{
console.log(val);
}).then((val)=>{
console.log(val);
})
</script>
打印结果如下:
7.6 异常传递穿透
1)当使用promise的then链式调用时,可以在最后指定失败的回调
2)前面任何一步操作出现异常,都会传到最后的失败中处理
相关代码:
<script>
let p = new Promise((resolve,reject)=>{
resolve()
})
p.then(()=>{
console.log('err');
reject()
}).then(()=>{
console.log('ok');
}).catch(()=>{
console.log('似乎出错了')
})
</script>
打印结果:
7.7 如何中断promise链
1)当使用promise的·then链式调用时,在中间中断,不再调用后面的回调函数
2)方法:在回调函数中返回一个pending状态的promise对象
相关代码:
<script>
let p = new Promise((resolve,reject)=>{
resolve()
})
p.then(()=>{
console.log(111);
return new Promise(()=>{})
}).then(()=>{
console.log(222);
}).then(()=>{
console.log(333);
})
</script>
打印结果:
8、async与await
8.1 MDN文档
8.2 Async函数
1)函数的返回结果为promise对象
2)promise对象的结果由async函数执行的返回值决定,与then类似
<script>
async function main(){
// 1.非promise,返回promise状态为成功,结果为返回的结果
// return 'ok'
// 2.为promise对象,返回的结果为promise的结果、
return new Promise((resolve,reject)=>{
reject('error')
})
// 3.抛出错误
// throw '出了问题'
}
let result = main()
console.log(result);
</script>
8.3 await表达式
1)awat 右侧的表达式一般为promise对象,但也可以是其他的值
2)如果表达式是promise对象,awai返回的是promise成功的值
3)如果表达式是其他值,直接将此值作为await的返回值
注意:
①await必须写在async函数中,但async函数中可以没有await
②如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
<script>
async function main(){
let p = new Promise((resolve,reject)=>{
resolve('ok')
})
let p1 = new Promise((resolve,reject)=>{
reject("Error")
})
let res1 = await p
let res2 = await 'success'
console.log(res1);
console.log(res2);
try{
let res3 = await p1
}catch (e){
console.log(e)
}
}
main()
</script>
打印结果:
完结,撒花!!!!