Promise
回调地狱
在回答这个问题之前,我们先来聊一聊回调地狱,我们都知道Promise是用来解决回调地狱的,那么什么是回调地狱呢?我先用一个简单的例子说明一下 比如你正在马路等红绿灯,那么红绿灯的顺序一定是红灯-黄灯-绿灯,在代码中可以这样表示
javascript
setTimeout(() => {
console.log("红灯");
setTimeout(() => {
console.log("黄灯");
setTimeout(() => {
console.log("绿灯");
},1000)
},1000)
},1000)
上面的段代码就是对回调地狱的一个简单描述,当后一个行动需要等待上一个结果时,会一层一层的嵌套下去,这只是一个简单的描述,想象一下,如果上面这段代码丰富起来会变成什么样,比如红灯的时候马路的车会停下来,人会在斑马线等待...,或者绿灯之后还能继续嵌套,这样的代码可读性会变得非常差,所以这个时候Promise应运而生
Promise的描述
在说这个之前先感谢袁进老师的讲解,这里附上链接 www.bilibili.com/video/BV1qu...
promise有两套规范,一个是es6之前跟es6之后的,我们先来说es6之前的 在es6之前Promise是一个社区规范,叫做Promise A+,A+规范说明了Promise就是一个带then方法的对象或者函数,并且Promise之间可以互相通信 到了es6之后官方吸收了这些民间标准,并新增了一些方法,更新了一个构造函数--new Promise(),我们通过这个构造函数创建的实例化对象来满足Promise规范 总的来说es6之前Promise A+就是一个带then方法的对象或者函数,在es6后,它是一个构造函数,通过它创建的实例满足了Promise A+规范,只要满足了Promise A+规范,它们之间就可以互相操作,还可以使用es7中的async跟await
Promise的用法
创建Promise
使用new Promise(executor)的构造函数创建,这里的executor是一个函数,他有两个形参resolve和reject,executor函数内部执行异步操作,成功调用resolve,失败调用reject
javascript
//创建Promise实例
let p=new Promise(function(resolve,reject){
let flag=true;
if(flag){//假设异步操作成功
resolve("成功");//此时Promise状态从pending变为fulfilled,并将结果传递出去
} else {
reject("失败")//将Promise状态从pending变成rejected,并将错误信息传递出去
}
})
Promise的状态
Promise的核心是一个状态机,一共有三种状态:
- Pending(等待)
- Fulfilled(完成)
- Rejected(拒绝)
状态一旦改变就不能再变:
- Pending -> Fulfilled
- Pending -> Rejected
使用Promise
通过.then()、.catch()、finally()方法处理结果或者错误
then(onFulfilled,onRejected)
then方法内部接收两个函数
- 当Promise状态变为 已完成(fulfilled) 时,调用onFulfilled函数,这个函数会接收resolve传递过来的值作为参数
- 当Promise状态变为 已拒绝(rejected) 时,调用onRejected函数,这个函数会接收reject传递过来的值作为参数
javascript
p.then(function (res){
//处理成功
console.log(res);
}, function (err){
//处理失败
console.log(err);
})
catch(onRejected)
catch方法是ES6规范中新增的,在Promise A+规范中并没有规定。它相当于.then(null, onRejected),专门用于处理失败状态。推荐使用.catch()来处理错误,因为它可以捕获前面所有.then()方法中的错误,并且更接近同步的try/catch代码风格。
javascript
p.then(function (res) {
//处理成功
console.log(res);
}).catch(function (err) {
//处理失败
console.log(err);
})
finally(onFinally)
无论Promise最终状态是成功还是失败,都会执行onFinally函数
javascript
p.finally(function() {
console.log("无论成功或失败,都会执行");
});
Promise解决回调地狱
还是以上面红绿灯为例
javascript
function light(time, color) {
//这里只模拟成功状态,time用来模拟现实中的网络请求快慢
return new Promise(function (resolve) {
setTimeout(function () {
resolve(color)
}, time)
})
}
light(1000, "红灯")
.then(function (res) {
console.log(res);
return light(1000, "黄灯");// 返回新Promise
// 只有上面返回的light函数状态变为已完成(fulfilled)才会执行下面的.then()方法
}).then(function (res) {
console.log(res);
return light(1000, "绿灯");
}).then(function (res) {
console.log(res);
})
这样代码就会变成链式调用,避免了层层嵌套,提高了可读性
async/await
谈到Promise同样离不开async跟await,它是es7引入的语法糖,是解决回调地狱的终极方案,可以使异步代码看起来像同步代码 async用来修饰一个函数,被修饰的函数默认返回值不再是undefined,而是会返回一个Promise await只能在async修饰的函数内部使用,它会暂停await下面的代码执行,等待Promise完成 将我们上面封装的函数加上async跟await:
ini
async function trafficLight() {
let light1 = await light(1000, "红灯");
console.log(light1);
let light2 = await light(1000, "黄灯");
console.log(light2);
let light3 = await light(1000, "绿灯");
console.log(light3);
}
trafficLight();
通过Promise和async/await,我们可以优雅地解决JavaScript中的异步编程问题,避免回调地狱,使代码更加清晰和易于维护