JS基础知识总结(八):这次聊聊Promise对象
“ 关注 前端开发社区
,回复"1"
即可加入 前端技术交流群
,回复 "2"
即可免费领取 500G前端干货!
Promise
是CommonJS提出的一种规范,在ES6中已经原生支持Promise
对象,非ES6环境可以用Bluebird
等库来支持。
引入
在js中任务的执行模型有两种:同步模式
和异步模式
。
同步模式:后一个任务B等待前一个任务A结束后,再执行。任务的执行顺序和任务的排序顺序是一致的。
异步模式:每一个任务有一个或多个回调函数,前一个任务A结束后,不是执行后一个任务B,而是执行任务A的回调函数。而后一个任务B是不等任务A结束就执行。任务的执行顺序,与任务的排序顺序不一致。
异步模式编程有四种方法:
回调函数(最基本的方法,把B写成A的回调函数)、 事件监听(为A绑定事件,当A发生某个事件,就执行B)、 发布/订阅 本文要介绍的Promise对象。
Promise是一个用于处理异步操作的对象,可以将回调函数写成链式调用的写法,让代码更优雅、流程更加清晰,让我们可以更合理、更规范地进行异步处理操作。它的思想是,每一个异步任务返回一个
Promise
对象,该对象有一个then
方法,允许指定回调函数。
1.Promise的基本知识
1.1 三种状态
Pending:进行中,刚创建一个Promise实例时,表示初始状态;
resolved(fulfilled):resolve方法调用的时候,表示操作成功,已经完成;
Rejected:reject方法调用的时候,表示操作失败;
1.2 两个过程
这三种状态只能从pendeng-->resolved(fulfilled),或者pending-->rejected,不能逆向转换,也不能在resolved(fulfilled)和rejected之间转换。并且一旦状态改变,就不会再改变,会一直保持这个结果。
汇总上述,创建一个Promise的实例是这样的:
//创建promise的实例let promise = new Promise((resolve,reject)=>{
//刚创建实例时的状态:pending
if('异步操作成功'){
//调用resolve方法,状态从pending变为fulfilled
resolve();
}else{
//调用reject方法,状态从pending变为rejected
reject();
}
});
1.3 then()
用于绑定处理操作后的处理程序,分别指定fulfilled
状态和rejected
状态的回调函数,即它的参数是两个函数,第一个用于处理操作成功后的业务,第二个用于处理操作失败后的业务。
//then()promise.then((res)=> {
//处理操作成功后的业务(即Promise对象的状态变为fullfilled时调用)
},(error)=> {
//处理操作失败后的业务(即Promise对象的状态变为rejected时调用)
});
1.4 catch()
用于处理操作异常的程序,catch()
只接受一个参数
//catch()promise.catch((error)=> {
//处理操作失败后的业务
});
一般来说,建议不要在then()里面定义rejected状态的回调函数,而是将then()用于处理操作成功,将catch()用于处理操作异常。因为这样做可以捕获then()执行中的错误,也更接近同步中try/catch的写法:
//try-catch// bad
promise.then((res)=> {
//处理操作成功后的业务
}, (error)=> {
//处理操作失败后的业务
});
// good
promise
.then((res)=> {
//处理操作成功后的业务
})
.catch((error)=> {
//处理操作失败后的业务
});
1.5 all()
接受一个数组作为参数,数组的元素是Promise实例对象。只有当参数中的实例对象的状态都为fulfilled
时,Promise.all( )才会有返回。
实例代码(可直接在浏览器中打开):
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise实例</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = () => {
//创建实例promise1
let promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve('promise1操作成功');
console.log('1')
}, 3000);
});
//创建实例promise1
let promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve('promise1操作成功');
console.log('2')
}, 1000);
});
Promise.all([promise1, promise2]).then((result) => {
console.log(result);
});
}
</script>
</head>
<body>
<div></div>
</body>
</html>
结果(注意看时间):
代码说明:
1s后,promise2进入fulfilled状态,间隔2s,也就是3s后,promise1也进入fulfilled状态。这时,由于两个实例都进入了
fulfilled
状态,所以Promise.all()才进入了then方法。
使用场景:执行某个操作需要依赖多个接口请求回的数据,且这些接口之间不存在互相依赖的关系。这时使用
Promise.all()
,等到所有接口都请求成功了,它才会进行操作。
1.6 race()
和all()的参数一样,参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。
实例代码(可直接在浏览器中打开):
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise实例</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = () => {
//创建实例promise1
let promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve('promise1操作成功');
console.log('1')
}, 3000);
});
//创建实例promise1
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('promise1操作失败');
console.log('2')
}, 1000);
});
Promise.race([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
})
}
</script>
</head>
<body>
<div></div>
</body>
</html>
结果(注意看时间):
代码说明:
1s后,promise2进入rejected状态,由于一个实例的状态发生了变化,所以Promise.race()就立刻执行了。
2 实例
平时开发中可能经常会遇到的问题是,要用ajax进行多次请求。例如现在有三个请求,请求A、请求B、请求C。请求C要将请求B的请求回来的数据做为参数,请求B要将请求A的请求回来的数据做为参数。
按照这个思路,我们可能会直接写出这样的层层嵌套的代码:
//------请求A 开始--------- $.ajax({
success:function(res1){
//------请求B 开始----
$.ajax({
success:function(res2){
//----请求C 开始---
$.ajax({
success:function(res3){
}
});
//---请求C 结束---
}
});
//------请求B 结束-----
}
});
//------请求A 结束---------
在请求A的success后,请求B发送请求,在请求B 的success后,请求C发送请求。请求C结束后,再向上到请求B结束,请求B结束后,再向上到请求A结束。
这样虽然可以完成任务,但是代码层层嵌套,代码可读性差,也不便于调试和后续的代码维护。而如果用Promise,你可以这样写(示意代码,无ajax请求):
此处附上完整可执行代码,可在浏览器的控制台中查看执行结果:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<title>Promise实例</title>
<style type="text/css"></style>
<script type="text/javascript">
window.onload = () => {
let promise = new Promise((resolve, reject) => {
if (true) {
//调用操作成功方法
resolve('操作成功');
} else {
//调用操作异常方法
reject('操作异常');
}
});
//then处理操作成功,catch处理操作异常
promise.then(requestA)
.then(requestB)
.then(requestC)
.catch(requestError);
functionrequestA() {
console.log('请求A成功');
return'下一个是请求B';
}
function requestB(res) {
console.log('上一步的结果:' + res);
console.log('请求B成功');
return'下一个是请求C';
}
function requestC(res) {
console.log('上一步的结果:' + res);
console.log('请求C成功');
}
functionrequestError() {
console.log('请求失败');
}
}
</script>
</head>
<body>
<div></div>
</body>
</html>
结果如下:
可以看出请求C依赖请求B的结果,请求B依赖请求A的结果,在请求A中是使用了return将需要的数据返回,传递给下一个then()中的请求B,实现了参数的传递。同理,请求B中也是用了return,将参数传递给了请求C。
3.小结
本文主要介绍了Promise
对象的三个状态和两个过程。“三个状态”是:初始化
、操作成功
、操作异常
,“两个过程”是初始化状态
到操作成功状态
,和初始化状态到操作异常状态。除此之前,还有两种实例方法:then()、catch()来绑定处理程序。类方法:Promise.all()
、Promise.race()
。如有问题,欢迎指正。
最近几天会陆续更新的~~,觉得总结的可以的话,麻烦给小编点一个 在看
, 谢谢!
往期:
JS基础知识" title="JS基础知识">JS基础知识总结(七):聊聊ajax的创建过程
JS基础知识总结(六):只知道ajax?你已经out了
JS基础知识总结(五):防抖和节流
JS基础知识总结(四):作用域与闭包
JS基础知识总结(三):原型、原型链
请各位帅哥美女多多支持帅编,回复“1”
即可加入前端技术交流群,回复"2"
即可领取 500G 前端干货
本文使用 mdnice 排版
以上是 JS基础知识总结(八):这次聊聊Promise对象 的全部内容, 来源链接: utcz.com/a/27512.html