Promise
用法
new Promise((resolve , reject) => {
//...此处执行你的代码
// resolve("成功") -> 执行成功回调
// reject("失败") -> 执行失败回调
}).then(res => {
console.log(res) //输出: 成功
}).catch(err => {
console.log(err) //输出: 失败
})
// 不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
.finally(() => {
console.log('finally');
});
在这里 先了解一下promise的三种状态
:
- pending: 初始值
- fulfilled: 代表操作成功
- rejected: 代表操作失败
业务场景: 想要实现异步操作,比如你需要获取一个接口的参数后,才执行后面的操作
附上例子
function getData () {
return new Promise((resolve , reject) => {
// ...这里调用获取数据接口
//假设获取的数据是data
let data = '数据'
resolve(data)
})
}
getData().then(res => {
console.log(res) //这里拿到上面接口数据
// ...执行拿到数据后的操作
})
async、await
async
在函数前面加上async关键字,表示这是一个异步函数
async function doit() {
return 'to doit'
}
doit() //为了判断他不会阻塞后面的代码执行,在他后面输出一句话
console.log('我在后面,但是我会先执行')
控制台输出
这里看出他确实不会阻塞后面的代码执行,但是调用了doit函数,没有输出,打印一下这个函数,看看会输出什么。
async function doit() {
return 'to doit'
}
console.log(doit())
console.log('我在后面,但是我会先执行')
控制台输出
这里控制台打印的是一个promise对象
,说明async返回的是一个promise对象
,那么我们现在再来写个then方法来获取promise的返回值
async function doit() {
return 'to doit'
}
doit().then(res => {
console.log(res)
})
console.log('我在后面,但是我会先执行')
控制台输出
我们获取到了doit函数的返回值,而且和上面说的一致,也没有阻塞后面代码的执行。
注意刚刚控制台打印出的promise对象的状态是fulfilled
, 回想一下文章开头介绍的promise三种状态,我们这里修改一下函数,让他能处理promise对象返回的成功
和失败
状态
async function doit(flag) {
if (flag) {
return 'to doit'
} else {
throw 'not to doit'
}
}
doit(false).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
doit(true).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
控制台输出
运行过程: 第一次调用doit函数时,传入的flag为false,返回一个决议为失败的promise对象,执行失败的回调;
第二次调用doit函数时,传入flag为true,返回一个决议为成功的promise对象,执行成功回调。
await
学会了async关键字的用法,再来看看await关键字。
await关键字只能放async函数里面,他后面可以放任何表达式,一般我们会放一个返回promise对象的表达式。
// 2s后返回一个双倍的值
function doubleResult(num) {
return new Promise((resolve , reject) => {
setTimeout(() => {
resolve(num*2)
},2000)
})
}
// 写一个async函数,可以用到这里的await关键字
async function getDoubleResult() {
let result = await doubleResult(5)
console.log(result)
}
getDoubleResult() //2s后获得了数字10
这里getDoubleResult异步函数遇到await关键字,代码就暂停执行了,等待await右边的表达式执行完毕,promise决议为resolve了,拿到返回值,然后代码暂停结束,开始继续执行。
但是,这样呢还不能明显的看出async await的作用
// 加定时器的作用是为了更直观的看出异步执行
function fn1 (num) {
return new Promise ((resolve , reject) => {
setTimeout(() => {
resolve(num*2)
},3000)
})
}
function fn2 (num) {
return new Promise ((resolve , reject) => {
setTimeout(() => {
resolve(num*2)
},2000)
})
}
function fn3 (num) {
return new Promise ((resolve , reject) => {
resolve(num*2)
})
}
async function test() {
let num1 = await fn1(5)
let num2 = await fn2(10)
let num3 = await fn3(20)
console.log(num1+num2+num3) // 5s后控制台打印出 70
}
test()
这里我们可以看到代码按照我们写的顺序依次执行的,就像在写同步代码一样,再也没有回调地域了
特别注意
:如果promise没有一个成功的值传入,对await来说就算是失败了,下面的代码就不会执行
所以不管await后面的代码是同步还是异步,await总是需要时间,从右向左执行,先执行右侧的代码,执行完后,发现有await关键字,于是让出线程,阻塞代码
最后说一个小知识点,Promise本身是同步的,他的回调then和catch是异步的
关于同步和异步的问题,下一篇文章再来详细探讨~~
参考:https://www.cnblogs.com/yuanyingke/p/10280681.html