promise的学习使用
产生背景:
JS 作为单线程事件循环模型,异步编程可以缩短计算量较大的操作时间,并且可以避开某步操作阻塞线程执行。
早期的异步编程模式是通过定义回调函数来表明异步操作完成。串联多个异步操作需要深度嵌套的回调函数来解决。
一、认识
概念:ES6异步编程解决方案
作用:常用于封装ajax异步请求
底层:创建了Promise构造函数,并且给该构造函数绑定了then、catch、finally等原型方法,和reject、resolve、all、race等静态方法。
二、promise对象三种状态
Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.
语法:
var p = new Promise(function(resolve,reject){})
resolve 代表 决定(成功); reject 代表 失败
const p = new Promise((resolve, reject) => {
// 发送异步请求
// 默认触发的 所以是进行中状态
})
追问:为什么状态不可逆
回答:底层Promise构造函数中会判断当前是否是pending进行中状态,不是就会终止代码执行 所以不可逆.
追问:状态之间怎么转换?
回答:通过promise的then机制,来实现状态切换
三、使用
const p = new Promise(function(resolve,reject){
setTimeout(function(){
// resolve('我是成功的')
reject('这是失败的');
},2000)
};
p.then(function(data){
console.log('resolved成功回调');
}).catch(function(reason, data){
console.log('catch到rejected失败回调');
});
常用模式:
1. promise对象作为函数返回值
let promiseFn =()=>{
console.log('点击方法被调用')
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成Promise');
resolve('成功的时候调用');
}, 2000);
});
return p
}
promiseFn().then(function(data){
console.log(11111)
}).catch(function(data){
console.log(2222)
})
2. 结合ajax使用
串联请求场景下,当第一次发送的网络请求得到的数据,为第二次请求所必须的数据,使用promise
Promise 链式调用
+ 当你在第一个 then 内部返回一个新的 Promise 对象的时候可以把新的 Promise 的 then 连续书写
pAjax({ url: 'http://localhost:8888/test/first' })
.then(res => {
console.log(res)
// 这里是第一个请求完成后会执行的代码
// 调用 pAjax, 创建的第二个 承若(Promise)
// 在第一个 then 里面把新的 Promise return 了
return pAjax({ url: 'http://localhost:8888/test/second', dataType: 'json' })
})
.then(res2 => {
console.log(res2)
// 这里是第二个请求完成后会执行的代码
// 调用 pAjax, 创建第三个 承诺(Promise)
// 在第二个 then 里面被写的 Promise return 了
return pAjax({ url: 'http://localhost:8888/test/third', data: 'name=Jack&age=20', dataType: 'json' })
})
.then(res3 => console.log(res3))
其他技巧:
1. 期约合并
方法一:promise.all()
概念:所有的异步请求完成才执行
案例:一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
let wake = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time / 1000}秒后醒来`)
}, time)
})
}
let p1 = wake(3000);
let p2 = wake(2000);
// 只有两次调用promise都执行完毕,才会执行all
Promise.all([p1, p2]).then((result) => {
console.log(result) // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
console.log(error)
})
方法二:promise.race()
概念:Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
2. 增强语法:async 和 await 关键字
async function fn() {
console.log('start')
// 等着第一个请求
const r1 = await pAjax({ url: 'http://localhost:8888/test/first' })
console.log(r1)
// 如果上面的 请求没有结束, 那么这里的代码不会执行
// 这里的代码执行了, 一定是因为 await 等到了上面的请求结束
const r2 = await pAjax({ url: 'http://localhost:8888/test/second', dataType: 'json' })
console.log(r2)
const r3 = await pAjax({ url: 'http://localhost:8888/test/third', data: 'name=Jack&age=20', dataType: 'json' })
console.log(r3)
console.log('end')
}