文章目录
Promise
理解
- 抽象表达
- Promise是一门新的技术
- Promise是JS中进行异步编程的新解决方案
- 旧方案是单纯使用回调函数
- 具体表达
- 从语法上来说:Promise是一个构造函数
- 从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
Promise的状态改变
- 实例对象中的一个属性 PromiseState
- pending变为resolved
- pending变为rejected
说明
- 只有这两种,且Promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据
- 成功的结果数据一般称为value
- 失败的结果数据一般称为reason
Promise对象的值
- 实例对象中的另一个属性 PromiseResult
- 保存着对象成功或失败的结果
- resolve
- reject
Promise基本使用
<!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>抽奖</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.container {
color: black;
position: relative;
}
</style>
</head>
<body>
<div class="container">
<h2 class="page-header">Promise 抽奖</h2>
<button class="btn-btn-promise" id="btn">点击抽奖</button>
</div>
<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)
//Promise形式实现
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100);
if(n <= 30) {
resolve();
} else {
reject();
}
}, 1000);
});
//调用then方法
p.then(() => {
alert('恭喜中奖!');
}, () => {
alert('再接再厉!');
});
});
</script>
</body>
</html>
Promise的基本流程
为什么要使用Promise
指定回调函数的方式更加灵活
- 旧的:必须在启动异步任务前指定
- Promise:启动异步任务 => 返回Promise对象 => 给Promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
支持链式调用,可以解决回调地狱问题
如何使用Promise
API
-
Promise构造函数:Promise(excutor){}
- executor函数:执行器(resolve, reject) => {}
- resolve函数:内部定义成功时我们调用的函数value => {}
- reject函数:内部定义失败时我们调用的函数reason => {}
- 说明
- executor会在Promise内部立即同步调用,异步操作在执行器中执行
-
Promise.prototype.then方法:(onReasolved, onRejected) => {}
- onResolved函数:成功的回调函数(value) => {}
- onRejected函数:失败的回调函数(reason) => {}
- 说明
- 指定用于得到成功value的成功回调和用于得到失败reason的失败回调返回一个新的promise对象
-
Promise.prototype.catch方法:(onRejected) => {}
- onRejected函数:失败的回调函数(reason) => {}
- 说明
- then()的语法糖,相当于:then(undefined, onRejected)
-
Promise.resolve方法:(value) => {}
- value:成功的数据或promise对象
- 说明
- 分会一个成功或失败的promise对象
-
Promise.reject方法:(reason) => {}
- reason:失败的原因
- 说明
- 返回一个失败的promise对象
-
Promise.all方法:(promise) => {}
- promise:包含n个promise的数组
- 说明
- 返回一个新的Promise,只有所有的Promise都成功才成功,只要有一个失败了就直接失败
-
Promise.race方法:(Promise) => {}
- Promise:包含n个Promise的数组
- 数组
- 返回一个新的Promise,第一个完成的Promise的结果状态就是最终的结果状态
Promise的几个关键问题
- 如何改变Promise状态?
- resolve(value):如果当前是pending就会变成resolved
- reject(reason):如果当前是pending就会变成rejected
- throw抛出异常:如果当前是pending就会变为rejected
- 一个Promise制定多个成功/失败回调函数,都会调用吗?
- 当Promise改变为对应状态时都会调用
- 改变Promise状态和指定回调函数谁先谁后?
- 都会可能,正常情况下是先指定回调再改变状态,但也可以先该状态再指定回调
- 如何先改状态再指定回调?
- 在执行器中直接调用resolve()/reject()
- 延迟更长时间才调用then()
- 什么时候才能得到数据?
- 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
- 如果先改变的状态,那当执行回调时,回调函数就会调用,得到数据
- Promise.then()返回的信Promise的结果状态由什么决定?
- 简单表达:由then()指定的回调函数执行的结果决定
- 详细表达
- 如果抛出异常,新Promise变为rejected,reason为抛出的异常
- 如果返回的是非Promise的任意值,新Promise变为resolved,value返回值
- 如果返回的是另一个新的Promise,此Promise的结果就会成为新Promise的结果
- Promise如何串连多个操作任务?
- Promise的then(返回一个新的Promise,可以开诚then()的链式调用
- 通过then的链接调用串连多个同步/异步任务
- Promise异常传透?
- 当使用Promise的then链式调用时,可以在最后指定失败的回调
- 前面任何操作出了异常,都会传到最后失败的回调中处理
- 中断Promise链?
- 当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数
- 办法:在回调函数中返回一个pending状态的Promise对象
return new Promise(() => {});
自定义Promise
定义整体结构
class Promise {
//构造方法
constructor(executor) {
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//声明属性
this.callbacks = [];
//保存实例对象的this值
const self = this;
//resolve函数
function resolve(data) {
//判断
if (self.PromiseState !== 'pending') return;
//1. 修改对象的状态-promiseState
self.PromiseState = 'fulfilled';
//2. 设置对象结果值-promiseResult
self.PromiseResult = data;
//调用成功的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data);
});
});
}
//reject函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
//1. 修改对象的状态-promiseState
self.PromiseState = 'rejected';
//2. 设置对象结果值-promiseResult
self.PromiseResult = data;
//调用失败的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data);
});
});
}
try {
//同步调用 执行器函数
executor(resolve, reject);
} catch (error) {
//修改promise对象状态为 失败
reject(error);
}
}
//then方法封装
then(onResolved, onRejected) {
const self = this;
//判断回调函数参数
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
if (typeof onResolved !== 'function') {
onResolved = value => value;
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type) {
try {
let result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(v => {
result(v);
}, r => {
reject(r);
});
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
//调用回调函数
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved);
});
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected);
});
}
//判断pending状态
if (this.PromiseState === 'pending') {
//保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
}
});
}
})
}
//catch方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
//添加resolve方法
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => {
result(v);
}, r => {
reject(r);
});
} else {
resolve(value);
}
});
}
//添加reject方法
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
//添加all方法
static all(promises) {
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for (let i = 0; i < promises.length; i++) {
//
promises[i].then(v => {
//得知对象的状态是成功
//每个promise对象都成功
count++;
//将当前promise对象成功的结果存入到数组中
arr[i] = v;
//判断
if (count === promises.length) {
//修改状态
resolve(arr);
}
}, r => {
reject(r);
})
}
});
}
//添加race方法
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
//修改返回对象的状态为-成功
resolve(v);
}, r => {
//修改返回对象的状态为-失败
reject(r);
})
}
});
}
}
async与await
async函数
- 函数的返回值为promise对象
- promise对象的结果有async函数执行的返回值决定
await表达式
- await右侧的表达式一般为promise对象,但也可以是其他的值
- 如果表达式是promise对象,await返回的是promise成功的值
- 如果表达式是其他值,直接将此值作为await的返回值
注意
- await必须卸载async函数中,但async函数中可以没有await
- 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理