一、await和async
在ES2017中,引入了async函数,来方便异步操作。
特点
- async/await从上到下顺序执行。
- async/await可以传递的参数数量不受限制。参数被作为普通局部变量处理,可使用let或者const关键字定义的块级变量。
- 同步代码和异步代码可以一起编写,只是要注意异步过程需要包装成一个Promise对象并置于await关键字后面
- async/await是对Promise的改进,准确来说是语法糖,本质上还是Promise。
二、使用方法
使用async定义异步处理函数
async function testAsync(){
return "hello async"
}
console.log(testAsync())
//Promise { 'hello async' }
testAsync().then(r=>{
console.log(r)
})
我们直接用async关键字定义函数。我们把整个函数执行后的结果打印出来,它直接返回一个Promise对象,可以简便之前定义promise对象的写法,既然返回的是Promise对象,那么就可以直接使用then方法进行下一步操作。这就是被称为语法糖的原因。
而且不仅可以使用then方法,还可以在最后使用捕捉错误的catch方法。
async function testAsync(){
return "hello async"
}
console.log(testAsync())
//Promise { 'hello async' }
testAsync().then(r=>{
//打印出 hello async
console.log(r)
//抛出错误
throw new Error("this is a mistake")
}).catch(err=>{
//捕捉到错误
console.log(err)
})
async配合Promise使用
执行下列代码:
function testAsync(){
return "hello async"
}
function testPromise(){
return new Promise((resolve)=>{
setTimeout(() => {
resolve("hello Promise")
}, 3000);
//resolve("hello Promise")
})
}
//await 函数比如放在 async函数里面,await会等待 promise函数执行后resolve后的结果
async function test(){
var Async_1 = await testAsync()
var Promise_1 = await testPromise().then()
console.log(Async_1)
console.log(Promise_1)
}
test()
运行之后,效果是隔了三秒钟,同时打印。 你可以尝试把setTimeout注释掉,然后把注释的部分取消注释运行。发现也是同时打印
这是为什么呢??
因为await指令如果放在async函数里面,那么该指令会暂停当前异步函数的执行,并等待promise执行,,然后再执行异步函数,并返回结果。如果等待的不是promise对象,则返回该值本身
所以这里的代码执行顺序应该是:
- test()执行
- 暂停test()
- 执行await testAsync
- 执行 await testPromise().then()
- 执行test()
因为里面有await关键字,所以要暂停async function test()的执行。等待函数体里面的Promise执行结束后才继续执行。
三、总结
async 和 promise 的写法对比
async function func(){
return 'hello world'
}
console.log(func())
let p = new Promise((resolve,reject)=>{
resolve('hello world')
})
console.log(p)
这样写,虽然最后的打印的结果是一样的。但是第二个代码Promise对象的状态已经从pending 变成 fulfilled了,如果在then中抛出一个错误的话,也不会经过错误捕捉操作。从一开始就要决定状态, 然后根据状态去选择执行下一步。使用promise对象,如果第一步没有完成状态的选择,那么不会去执行then中的方法。
如果使用async的话,如果你在then中不抛出错误的话,它会默认按照fulfilled状态一直执行then中的方法,不会固定为fulfilled状态。只要你某个then方法中抛出错误,那么就直接跳过执行catch方法。
所以相比之下还是 async要更方便一点。
这是我下面实验的代码:
async function func(){
return 'hello world'
}
console.log(func().then(r=>{
console.log(r)
}).then(r=>{
console.log("1")
}).then(r=>{
console.log("2")
throw new Error("这是错误")
}).then(r=>{
console.log("3")
}).catch(err=>{
console.log(err)
}))
let p = new Promise((resolve,reject)=>{
console.log('1')
//一开始就要指定状态,如果不使用resolve,那么只会输出1,使用了resolve之后,输出 1 2,即使抛出错误,也无法处理。
resolve()
// throw new Error("错误")
}).then(r=>{
console.log("2")
}).catch(err=>{
// console.log(err)
})
console.log(p)