聊一聊Promise
ES6中的Promise
什么是Promise
Promise是异步编程的一种解决方案。
使用场景:一般情况是有异步操作时,使用Promise对这个异步操作进行封装
网络请求的回调地狱
多层请求的嵌套
$.ajax('url1', function (data1) {
$.ajax(data1['url2'], function (data2) {
$.ajax(data2['url3'], function (data3) {
$.ajax(data3['url4'], function (data4) {
console.log(data4);
})
})
})
})
代码不容易维护,复杂。
使用Promise就可以解决上面的问题,用优雅的方式来处理异步操作。
执行顺序
当执行new Promise时
👉构造函数(1.保存了一些状态信息 ,2.执行传入的参数),在执行传入的回调函数时,会传入两个参数,resolve
, reject
, 它两都是函数。
resolve
是成功时调用,反过来就有reject(拒绝)
new Promise((resolve, reject) => {
setTimeout(() => {
//成功的时候调用
resolve('我是promise')
}, 1000)
}).then((data) => {
console.log(data);
})
当代码执行到
resolve()
时,会执行then
,并把参数传给then
的data
.
new Promise((resolve, reject) => {
setTimeout(() => {
// 成功的时候调用
// resolve('我是promise')
//失败的时候调用
reject('error message')
}, 1000)
}).then((data) => {
console.log(data);
}).catch(err => {
console.log(err);
})
reject时拒绝时执行
,与resolve不同的是,它的下一步执行是到catch
里去执行。同样可以把reject
里的值传给err
Promise的另外一种写法
<script>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('nih')
reject('err')
}, 1000)
}).then(data => {
// 函数一,相当于成功的时候调用
console.log(data);
}, err => {
//函数二 ,相当于失败的时候调用
console.log(err);
})
</script>
这种写法不同于上面的方法在于,then函数里放置了两个函数,一个是请求成功调用的,另一种是请求失败的时候调用的。
定时器的异步事件
嵌套变成
变成链式编程
,异步处理效率更高。
- 嵌套编程
setTimeout(() => {
console.log('Hello World');
console.log('Hello World');
setTimeout(() => {
console.log('Hello pink');
console.log('Hello pink');
setTimeout(() => {
console.log('blue');
console.log('blue');
}, 1000)
}, 1000)
}, 1000)
- 链式编程
// 参数 ->函数(resolve,reject)
new Promise((resolve, reject) => {
//第一次网络请求的代码
setTimeout(() => {
resolve()
}, 1000)
}).then(() => {
//第一次处理的代码
console.log('Hello World');
console.log('Hello World');
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000);
}).then(() => {
console.log('Hello pink');
console.log('Hello pink');
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
}).then(() => {
console.log('blue');
console.log('blue');
})
})
})
肉眼可见的变成了链式,这只是用计时器模仿了一下异步请求的操作,重要的是
promise的使用
,以及体会到从嵌套到链式的转变
Promise三种状态
异步操纵后会有三种状态。
padding
:等待状态,比如正在进行网络请求,或者定时器没有到时间。fulfill
:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
reject
:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()
- 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
- 一个promise的状态只可能从
“等待”转到“完成”态或者“拒绝”态
,不能逆向转换
,同时“完成”态和“拒绝”态不能相互转换- promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
- then方法接受两个参数,
第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用
,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用
。同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
Promise链式调用
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一层的处理代码');
//new Promise(resolve => resolve(结果))简写
return Promise.resolve(res + '111')
return Promise.reject('error message')
//throw 'error message'
}).then(res => {
console.log(res, '第二层处理的代码');
// 省略掉Promise.resolve
return res + '222'
}).then(res => {
console.log(res, '第三层处理的代码');
//最原生的写法
return new Promise(resolve => {
resolve(res + '333')
})
}).then(res=>{
console.log(res, '第四层处理的代码');
})
注意观察Promise只在第一步进行了异步,同时注意
promise
的三种书写方式
,同时抛出错误信息不但可以使用Promise.reject('error')
,还可以通过throw 'error'
来抛出异常。
Promise的all方法
适用情况:需求
依赖两个或者多个
请求才可以完成。
Promise.all([
new Promise((resolve, reject) => {
$ajax({
url: 'url1',
success: function (data) {
console.log(data);
}
})
}),
new Promise((resolve, reject) => {
$ajax({
url: 'url2',
success: function (data) {
console.log(data);
}
})
})
]).then(results => {
results[0]
results[1]
})
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: 'liyu', age: 18 })
}, 1000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: 'kobe', age: 19 })
}, 2000)
})
]).then(results => {
console.log(results);
})
适用promise方法对
两次请求进行封装
,最终结果会保存到results的结果数组中,下标为0返回的是第一个结果,下标为1返回第二个结果。