前言:
在Es6之前我门对异步操作,大多用的都是异步函数,那些属于异步的操作呢? fs文件读取,数据库操作,AJAX,定时器。这些都属于异步。且看下图:
可以看到:代码非常的乱,也不便于阅读。这个时候Promise就派上用场了,且往下看,接下来让我们一起探究Promise吧。
一.Promise是什么?
(1)Promise是一门新的技术(Es6规范)
(2)Promise是一个构造函数
二.Promise的参数
(1)参数
let p = new Promise((resolve, reject) => {
}).then((res) => {}, rej => {})
resolve,reject代表成功,失败的函数,then里面的res和rej代表成功,失败的回调。
(2)代码
<!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>Document</title>
</head>
<body>
<button id="btn">点击抽奖</button>
<!-- 生成随机数 -->
<script>
function rand(m, n) {
return Math.ceil(Math.random() * (n - m + 1)) + m - 1
}
// 点击按钮,2s后显示是否中奖(30%概率中奖)
// 获取元素对象
const btn = document.querySelector('#btn')
btn.addEventListener('click', function () {
// setTimeout(() => {
// let n = rand(1, 100)
// if (n <= 30) {
// alert(`恭喜中奖`)
// } else {
// alert(`再接再厉`)
// }
// }, 1000);
// 异步任务成功:
// resolve 解决 函数类型的数据
// 异步任务失败:
// reject 拒绝 函数类型的数据
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100)
if (n <= 30) {
resolve(n) //将promise的状态设置成功
} else {
reject(n) //将promise的状态设置失败
}
}, 1000);
})
// 调用then方法
p.then((res) => {
alert(`恭喜中奖` + res)
}, (res) => {
alert(`再接再厉` + res)
})
})
</script>
</body>
</html>
可以看出里面还可以传递参数。
三.Promise的状态
(1)三种状态
peanding 等待
fullfilled 成功
reject 失败
(2)只存在两种状态的转换
pending----------------resolved
peding---------------rejected
说明:只有这2种,且一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据。
四.Promise的工作流程图
五.Promise的api
(1)同步调用
代码:
<body>
<script>
let p = new Promise((resolve, reject) => {
//同步调用
console.log(`111`);
})
console.log(`222`);
</script>
</body>
图:
结论:说明里面的代码是同步执行的。
(2)then方法
1.代码
then((res)=>{ 成功之后 },(err)=>{失败之后})
2.拿到成功之后的回到
3.拿到失败之后的回调
(2)catch方法
作用:只能指定失败之后的回调
代码:
<script>
let p = new Promise((resolve, reject) => {
reject(`error`)
})
p.catch(res => {
console.log(res);
})
</script>
(3)Promise.all方法
(1)组成:Promise组成的一个数组
(2)状态:如果数组里面的Promise都成功,返回的结果也是一个数组,失败就返回失败的结果。
(3)代码:
<script>
let p1 = new Promise((resovle, reject) => {
resovle(`ok`)
})
let p2 = Promise.resolve(`SUCCESS`)
let p3 = Promise.resolve(`Oh yeah`)
const result = Promise.all([p1, p2, p3])
console.log(result);
</script>
图示:
改变其中的一个状态为失败
let p3 = Promise.reject(`Oh yeah`)
图示:
(4)Promise.race方法
结果:谁先改变状态就先执行谁
代码:
let p1 = new Promise((resovle, reject) => {
resovle(`ok`)
})
let p2 = Promise.resolve(`SUCCESS`)
let p3 = Promise.resolve(`Oh yeah`)
const result = Promise.race([p1, p2, p3])
// p1先改变状态result的结果由p1来决定
console.log(result);
图示:
六.Promise.resolve方法
1. 作用:快速得到一个Promise对象
2.代码:
let p1 = Promise.resolve(521)
console.log(p1);
图示:
3.任意类型都得到的是一个成功状态的Promise对象,哪怕是一个underfined
1.代码:
<script>
let p1 = Promise.resolve(undefined)
console.log(p1);
</script>
图示:
4.如果传入的是一个Promise对象
<script>
let p1 = Promise.resolve(
new Promise((resolve, reject) => {
reject('error')
})
)
console.log(p1);
</script>
图示:
七.Promise.reject方法
1.作用:返回一个失败的Promise对象
2.代码:
let p = Promise.reject(521)
console.log(p);
图示:
3.无论如何传入的都是一个失败的状态,即使传入的是一个成功的promise对象
图示:
八.改变状态
1.peading---------------->resolve
代码:
let p = new Promise((resolve, reject) => {
resovle(`ok`)
})
console.log(p);
2.peading----------------->reject
let p = new Promise((resolve, reject) => {
reject('error')
})
console.log(p);
3.通过throw,peading----------------->reject
let p = new Promise((resolve, reject) => {
throw `出现错误`
})
console.log(p);
图示:
九.改变promise状态和指定回调函数谁先谁后
(1) 执行器函数为同步任务 ------------------->先改变状态
<script>
let p = new Promise((resolve, reject) => {
resolve('ok')
})
p.then(res => {
console.log(res);
})
</script>
(2) 执行器函数为异步任务----------------->先执行回调函数
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 2000);
})
p.then(res => {
console.log(res);
})
</script>
十.then方法
(1)如果是一个非Promise则结果是一个成功的promise。
代码:
let p = new Promise((resolve, reject) => {
resolve('ok')
})
let p1 = p.then(res => {
return 520
})
console.log(p1);
图示:
(2)如果是一个promise对象
代码:
<script>
let p = new Promise((resolve, reject) => {
resolve('ok')
})
let p1 = p.then(res => {
return new Promise((resolve, reject) => {
resolve('success')
})
})
console.log(p1);
</script>
图示:
如果是抛出一个错误 返回的是错误的对象
(3)串连多个任务
输出是underfined,虽然没有返回的结果,但是返回的是一个成功的promise,且是一个成功的underfined 。
十一.中断promise链的方法
有且只有一种方法,返回一个peading状态的对象
十二.async函数
1.用async修饰的函数是一个Promise对象
async function main() {
}
let res = main()
console.log(res)
图示:
2.如果返回的不是一个Promise对象,Promise对象的结果由async函数执行的返回值决定 。
代码:
<script>
async function main() {
return 521
}
let res = main()
console.log(res)
</script>
图示:
3. 如果返回的是一个Promise对象。
代码:
async function main() {
return new Promise((resolve, reject) => {
resolve('ok')
})
}
let res = main()
console.log(res);
图示:
十三.await函数
1.await右侧的表达式一般为promise对象,但也可以是其它的值
2.如果表达式是promise对象,await返回的是promise成功的值
3.如果表达式是其它值,直接将此值作为await的返回值
4.await必须写在async函数中,但async函数中可以没有await
5.如果await的promise失败了,就会抛出异常,需要通过try....catch捕获处理
6.实际应用
读取文件
发AJAX请求
7.如果表达式是promise对象,await返回的是promise成功的值
代码:
<script>
async function fn() {
return 521
}
async function main() {
let a1 = await fn()
console.log(a1);
}
main()
</script>
图示:
8.如果表达式是其它值,直接将此值作为await的返回值
代码:
async function fn() {
return 521
}
async function main() {
let a1 = await 100
console.log(a1);
}
main()
图示:
9.如果await的promise失败了,就会抛出异常,需要通过try....catch捕获处理
代码:
<!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>Document</title>
</head>
<body>
<script>
async function main() {
try {
let a1 = await Promise.reject(2)
console.log(a1);
} catch (e) {
console.log(e);
}
}
main()
</script>
</body>
</html>
图示: