什么是Promise呢?
ES6中一个非常重要和好用的特性就是Promise
- 但是初次接触Promise会一脸懵逼,这TM是什么东西?
- 看看官方或者一些文章对它的介绍和用法,也是一头雾水。
Promise到底是做什么的呢?
- Promise是异步编程的一种解决方案。
那什么时候我们会来处理异步事件呢? - 一种很常见的场景应该就是网络请求了。
- 我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7一样将结果返回。
- 所以往往我们会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去。
- 如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦。
但是,当网络请求非常复杂时,就会出现回调地狱。
OK,我以一个非常夸张的案例来说明。
网络请求的回调地狱
我们来考虑下面的场景(有夸张的成分):
- 我们需要通过一个url1从服务器加载一个数据data1,data1中包含了下一个请求的url2
- 我们需要通过data1取出url2,从服务器加载数据data2,data2中包含了下一个请求的url3
- 我们需要通过data2取出url3,从服务器加载数据data3,data3中包含了下一个请求的url4
- 发送网络请求url4,获取最终的数据data4
上面的代码有什么问题吗?
- 正常情况下,不会有什么问题,可以正常运行并且获取我们想要的结果。
- 但是,这样额代码难看而且不容易维护。
我们更加期望的是一种更加优雅的方式来进行这种异步操作。
如何做呢?就是使用Promise。 - Promise可以以一种非常优雅的方式来解决这个问题。
Promise基本语法
这里,我们用一个定时器来模拟异步事件:
假设下面的data是从网络上1秒后请求的数据
<script>
// 1.使用setTimeout 模拟异步请求
// 假如现在有三个嵌套的网络请求,一般的做法。这个时候的结构就相当的复杂了
setTimeout(() => {
console.log("Hello word")
console.log("Hello word")
console.log("Hello word")
// .. 此处省略1w行代码
setTimeout(() => {
console.log("hello vue.js")
console.log("hello vue.js")
console.log("hello vue.js")
// .. 此处省略1w行代码
setTimeout(() => {
console.log("hello java")
console.log("hello java")
console.log("hello java")
// .. 此处省略1w行代码
}, 1000)
}, 1000)
}, 1000)
</script>
console.log就是我们的处理方式。
这是我们过去的处理方式,我们将它换成Promise代码
<script>
new Promise((resolve, reject) => {
// 第一次网络请求代码
setTimeout(() => {
resolve() // 当执行这个函数时,就会调用下面的then函数
}, 1000)
}).then(() => {
// 第一次网络请求回调
console.log("Hello word")
console.log("Hello word")
console.log("Hello word")
// .. 此处省略1w行代码
// then() 的返回值 又是一个Promise
return new Promise((resolve, reject) => {
// 第二次网络请求
setTimeout(() => {
resolve() // 当执行这个函数时,就会调用下面的then函数
}, 1000)
})
}).then(() => {
console.log("hello vue.js")
console.log("hello vue.js")
console.log("hello vue.js")
// .. 此处省略1w行代码
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000)
})
}).then(() => {
console.log("hello java")
console.log("hello java")
console.log("hello java")
// // .. 此处省略1w行代码
})
// 所有的网络请求代码都放在Promise对象里面
// 所有的回调处理代码都放在上一次Promise对应的then()函数里面
</script>
一般情况下时有异步操作时才用到Promise对异步操作进行封装。
异步操作之后会有三种状态
我们一起来看一下这三种状态:
pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。
fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()
简单使用
new Promise((resolve, reject) => {
setTimeout(() => {
// 成功的时候调用resolve,执行then
resolve('resolve');
// 失败的时候调用reject,执行catch
reject('err');
}, 1000)
}).then((date) => {
console.log(date);
}).catch((err) => {
console.log(err)
})
另一种使用方式
new Promise((resolve, reject) => {
setTimeout(() => {
// 成功的时候调用resolve,执行then
resolve('resolve');
// 失败的时候调用reject,执行catch
reject('err');
}, 1000)
}).then((data) => {
// 成功时执行
console.log(data)
}, err => {
// 失败时执行
console.log(err)
})
Promise all的使用
当需要两个或以上网络请求同时都成功时。再执行回调
Promise.all([
new Promise((resolve, reject) => {
$.ajax({
url: 'url1',
success: function (data) {
resolve(data)
}
})
}),
new Promise((resolve, reject) => {
$.ajax({
url: 'url2',
success: function (data) {
resolve(data)
}
})
})
]).then((result => {
console.log(result[0]);// 第一次请求的结果
console.log(result[1]);// 第二次请求的结果
}))