Promise的实例方法
promise为我们提供了三个实例方法,then、catch、finally。这三个实例方法可以帮助我们在promise状态改变时便捷地进行处理。在开发过程中了解这三个实例方法的具体实现可以帮助我们更好的进行
then()
then方法在使用时我们需要最多编写两个形参,onFulfilled
和onRejected
,但由于这两个参数是互斥情况,所以至多只会有一个形参生效。
在使用then()
之前,我们需要知道如何处理then()的参数和返回值。
参数:
onFulfilled
: onFulfilled应该编写为一个回调函数形式,用于处理resolve()或上一个then()返回的参数。 如果onFulfilled不是一个函数,在编译时会自动替换为(x) => x。
onRejected
: onRejected()应该编写为一个回调函数形式,用于处理reject()或上一个then()返回的参数。如果onFulfilled不是一个函数,在编译时会自动替换为(x) => {throw x}。
返回值:
then方法在调用时会立即返回一个新的promise,且该promise的状态为padding,直到onFulfilled或onRejected对其进行处理。
示例:
javascript
const p1 = new Promise((resolve, rejected) => {
resolve("成功")
})
const p2 = new Promise((resolve, rejected) => {
rejected("失败")
})
const p3 = new Promise((resolve, rejected) => {
resolve(new Promise(resolve => resolve("new Promise 成功")))
})
const p4 = new Promise((resolve, rejected) => {
rejected(new Promise(resolve => resolve("new Promise 成功")))
})
p1.then((val) => {console.log("p1 " + val)}, (val) => {console.log("p1 " + val)})
p2.then((val) => {console.log("p2 " + val)}, (val) => {console.log("p2 " + val)})
p3.then((val) => {console.log("p3 " + val)}, (val) => {console.log("p3 " + val)})
p4.then((val) => {console.log("p4 " + val)}, (val) => {console.log("p4 " + val)})
返回值
shell
> "p1 成功"
> "p2 失败"
> "p4 [object Promise]"
> "p3 new Promise 成功"
由于then
是异步调用且涉及到入参的解析封装再处理,所以多个promise在调用then方法时返回顺序并不一定按照调用顺序。
catch()
catch方法是对then方法的一个封装,它实际上是调用then(undefined, onRejected)来进行错误处理。由于onFulfilled
处写入的undefined,所以catch无法只能处理onRejected事件。
参数:
onRejected
: onRejected()应该编写为一个回调函数形式,用于处理reject()或上一个then()传入的reason。如果onFulfilled不是一个函数,在编译时会自动替换为(x) => {throw x}。
返回值:
返回一个新的promise,这个promise状态是padding,等待onRejected
被调用。当onRejected
被调用后会根据此次调用返回的reason进行处理。
javascript
const p1 = new Promise((resolve, rejected) => {
rejected('p1 error')
}).catch((reason) => {console.log('p1 ' + reason)})
const p2 = new Promise((resolve, rejected) => {
throw new Error('error');
}).catch((reason) => {console.log('p2 ' + reason)})
const p3 = new Promise((resolve, rejected) => {
resolve('error')
throw new Error('error');
}).catch((reason) => {console.log('p3 ' + reason)})
const p4 = new Promise((resolve, rejected) => {
setTimeout((resolve, rejected) => {
rejected('error')
}, 1000)
}).catch((reason) => {console.log('p4 ' + reason)})
返回值:
javascript
> "p1 p1 error"
> "p2 Error: error"
// p3因为是在resolve之后抛出的错误所以catch不会进行处理
// p4是在异步函数内部抛出的错误,catch没能成功捕获。
catch()
能够对promise被拒绝时抛出的reason或报错进行处理,但是要注意异步函数内部抛出的错误以及resolve()之后抛出的错误无法捕获。
finally
和catch
相似,finally
实际上也是在内部调用then方法then(onFinally, onFinally)。 但是在创建finally方法时只需要传入一个回调函数作为形参,不用强制传入两个形参。 onFinally不接受任何参数,调用时不用关心promise的拒绝原因或兑现值。所以通常用于 状态管理。
finally通常不会修改原promise的状态,但在onFinally回调函数中抛出错误时,原promise状态 也会被拒绝。
示例:
javascript
let isLoading = false;
fetch(request) //模拟一个fetch请求
isLoading=ture //状态转换发起请求
.then((response) => {
return response.json();
})
.then((json) => {
console.log(json);
})
.catch((error) => {
console.error(error);
})
.finally(() => {
// 请求结束状态置为false
isLoading = false;
});
async和await
async和await是ES8增加的新特性,是promise的语法糖,使用async和await我们可以更好的对异步函数进行编写。
async
async通过结合function关键字便捷定义一个异步函数。 格式: async funcion。
每次调用异步函数时,都会返回一个新的 Promise 对象, 该对象将会被解决为异步函数的返回值,或者被拒绝为异步函数中未捕获的异常。 如果手动返回一个非promise对象,那么函数会在内部进行隐式封装使其为promise对象返回。
如果函数体内没有await关键字,那么该函数实则是同步执行。只有存在await关键字,该函数才会异步执行。
await
await操作符用于等待一个promise对象状态由padding转为onFulfilled或onRejected, 并获取其返回值。它只能在异步函数或顶层代码块里使用,在该promise状态转换前该函数不会往下执行。
await会获取从 Promise 实例或 thenable 对象取得的处理结果。 如果等待的值不符合 thenable,则返回表达式本身的值。
如果Promise返回一个rejected处理的结果,await会把拒绝的reason抛出。
示例
javascript
async function foo() {
const result1 = new Promise((resolve, reject) => {
console.log("this 1");
setTimeout(() => {resolve(1)}, 1000);
}).then(val => console.log(val))
const result2 = new Promise((resolve, reject) => {
console.log("this 2");
setTimeout(() => {resolve(2)}, 500);
}).then(val => console.log(val))
}
async function foo2() {
const result3 = await new Promise((resolve, reject) => {
console.log("this 3");
setTimeout(() => {resolve(3)}, 1000);
}).then(val => console.log(val))
const result4 = await new Promise((resolve, reject) => {
console.log("this 4");
setTimeout(() => {resolve(4)}, 500);
}).then(val => console.log(val))
}
foo();
foo2();
返回值:
shell
> "this 1"
> "this 2"
> "this 3"
> 2
> 1
> 3
> "this 4"
> 4
这个实例可以看出虽然foo和foo2都用async进行修饰,但是foo2()函数体内没有await关键字 两个promise依然是以状态变化的先后顺序来进行then方法的调用。
foo()函数体内由于用了await修饰,待result3完全执行完后再进行result4的调用。