Promise
回调地狱:代码在层级上,越套越深,很混乱,不易维护
回调两个主要缺陷:缺乏顺序性 和可信任性
setTimeout(() => {
console.log(1);
setTimeout(() => {
console.log(2);
setTimeout(() => {
console.log(3);
}, 1000)
}, 1000)
}, 1000);
于是提出Promise,可以让异步函数变得竟然有序,可能有人会说await和async也可以让异步函数同步执行,但是await操作符本来就是用于等待一个Promise对象的。
基础:
- 要先创建一个Promise对象,并将其作为函数值返回
- Promis构造函数要求传入函数,传入函数会立即执行,传入函数带有两个参数:resolve(成功回调函数)、reject(失败回调函数)
- promise的三个状态:pending(初始)、fulfilled(操作成功完成)、rejected(操作失败)
- .then(resovle, reject),第一个参数是成功回调,第二个参数就是失败回调。 如果只想处理成功,或者失败,对应参数可设置为null,只有一个参数则表示状态改变就执行,不区分状态结果。
- .then()的第二个参数传进去的是一个失败回调的函数,但是Promise还有一个.catch()的方法,也是用来处理失败的
- .then(resovle, reject)的reject按就近原则,只对最近的这个异步函数进行错误处理,但是对以后的或者之前的异步函数不做处理,而.catch(reject)会捕获到全局所有链式上异步函数的错误。catch是then(null,rejection)的语法糖, 也会返回一个新promise
链式调用:
- .then()可以一层一层的传一下去,这也是厉害的地方。
- .catch()紧跟在抛出错误的一步函数后面,会抛出错误,然后继续往下执行。
- .catch()会捕获全局错误,但是,.catch()写在最后,抛出错误以后,函数会直接跳到.catch()然后继续往下执行
⚠️❗️!!非常重要:关于.then的链式调用:
- ① then可以通过返回新的promise对象,来实现链式调用,但是返回的promise对象中一定要定义resolve(xxx),否则then无法往下执行【如果设置了定时,那么resolve(xxx)要放在定时函数内部,否则不会按顺序进行调用,而还是根据延时时间执行】;
- ② 如果then中返回常量,那么下一个then中接收的res就是这个常量;
- ③ 如果then中什么都没有返回,那么就返回undefined,下一个then的res就是undefined
Promise.all()
使各种不同的请求,都成功后再一起呈现在页面上
它会在所有成员的promise都完成(fulfilled)后才会完成(fulfilled)。返回的promise会收到一个完成消息,这是一个由所有传入promise的完成消息组成的数组,与指定的顺序一致。任意一个被拒绝(rejected),它就立刻进入被拒绝(rejected)状态。
// Promise.all()需要传入的就是一个数组,每一项就是每一个异步函数
function timeout(delay) {
return new Promise((resolve, reject) => {
setTimeout(resolve, delay * 1000)
})
}
Promise.all([
timeout(1),
timeout(3),
timeout(5),
]).then(() => {
console.log('都请求完毕了!')
});
Promise.race()
会监听所有的Promise对象,在等待其中的第一个进入完成状态的Promise对象。一旦有第一个Promise对象进入了完成状态,该方法返回的Promise对象便会根据这第一个完成的Promise对象的状态而改变 。
应用:1. 设置超时处理
// 前面定义的timeoutPromise(..)返回一个promise,
// 这个promise会在指定延时之后拒绝
// 为foo()设定超时
Promise.race( [
foo(), // 启动foo()
timeoutPromise( 3000 ) // 给它3秒钟
] ) .then(
function(){
// foo(..)按时完成!
},
function(err){
// 要么foo()被拒绝,要么只是没能够按时完成,
// 因此要查看err了解具体原因
}
);
- finally:前面例子中的 foo() 保留了一些要用的资源,但是出现了超时,导致这个 promise 被忽略,finally就是用来:超时后主动释放这些保留资源,或者取消任何可能产生的副作用。
Promise 需要一个 finally(..) 回调注册,这个回调在 Promise 决议后总 是会被调用,并且允许你执行任何必要的清理工作
其他变体:
- none: 类似于all,但是完成和拒绝的情况互换。所有promise都被拒绝,则进入fulfilled状态。
- any:类似于all,但是会忽略拒绝,只需要至少一个完成即可。
- first:类似于any,但是只选取第一个完成的promise。
- last:类似于first,但是只选取最后一个完成的promise。
- async-await
-
async:一个标志,表示函数是异步的,函数会返回一个Promise对象,可以使用then方法添加回调函数
-
await:必须出现在async函数内部。后面可以跟任何的js表达式,用来等待Promise对象的状态被resolved。如果是promise对象,则会造成异步函数暂停执行,直到promise执行完毕再执行后面的语句。
-
实例:有三个请求需要发生,第三个请求是依赖于第二个请求的解构第二个请求依赖于第一个请求的结果。若用 ES5实现会有3层的回调,若用Promise 实现至少需要3个then。一个是代码横向发展,另一个是纵向发展。async-await就很简单清晰。