首先,要明白异步跟同步,参考下方博客的案例介绍:async/await让异步操作同步执行的方法详解 - dreamw - 博客园 (cnblogs.com)https://www.cnblogs.com/wl-blog/p/15136449.html
function fn1(){
console.log(111)
setTimeout(function(){
console.log('wait me 3000')
},3000)
}
function fn2(){
console.log(222)
}
fn1();
fn2();
//输出结果:
//111
//222
//wait me 3000
这里的setTimeout方法就是异步操作,它会在同步操作之后才执行,所以在执行了fn1后,同步执行了fn2,最后才执行setTimeout方法
你可能会想,这个setTimeout延时了3秒才执行,肯定比fn2慢,那下面把延时时间设为0看一下
function fn1(){
console.log(111)
setTimeout(function(){
console.log('wait me 0')
},0)
}
function fn2(){
console.log(222)
}
fn1();
fn2();
//运行结果:
//111
//222
//wait me 0
即使设置的等待时间是0,仍然会被当作异步方法,要等到同步方法执行完才会执行它
function fn1(){
console.log(111)
//通过设置setTimeout=>0,不延时执行方法,但是能将fn2放到同步方法执行完之后再执行
//也就是等到fn1,fn3执行完,再执行fn2,即使fn2再fn1中
setTimeout(fn2,0)
}
function fn2(){
console.log(222)
}
function fn3(){
console.log(333)
}
fn1();
fn3();
//输出结果:
//111
//333
//222
这样,既可以不延时调用fn2方法,又可以修改fn2方法的调用顺序,在fn1方法和fn3方法执行完后再调用fn2方法。
以上就是对异步、同步的简单举例,接下来重点说明一下如何通过async、await 或者promise.then()来讲异步操作同步化
async:它修饰的方法,返回的数据就会是个promise对象(可单独使用)
await:意思是等待执行完它修饰的方法,再往下执行,它会阻塞后面的代码,也就是同步
async function fn(){
return '111'
}
console.log(fn()); //Promise { '111' }
或者:
fn().then(data=>{
console.log(data) //111
}
使用async修饰的方法就会返回promise对象,
如果一个函数加了async关键词,这个函数又有返回值,在调用这个函数时,如果函数执行成功,内部会调用Promise.resolve()方法返回一个Promise对象,如果函数执行出现异常,就会调用Promise.reject()方法返回一个promise 对象
- 要想获取到async函数的执行结果,就要调用Promise.then()
function f() {
//最好是将方法返回成promise对象,用resolve,不然些复杂的函数,会导致await没效果
return new Promise(resolve =>{
resolve('hhh')
})
}
async function doSomething1(){
let x = await f();
return x
}
doSomething1().then(res=>{
console.log(res)
})
打印结果:
hhh
1、函数前面会加一个async修饰符,就会证明这个函数是一个异步函数;(也就是说这里的doSomething1函数是个异步函数)
2、await 是个运算符,用于组成表达式,它会阻塞后面的代码(也就是说这里的f()函数被转换成了同步函数,即使里面有异步方法,也会执行完再往下执行)
3、await 如果得到的是 Promise 对象,则得到其 resolve值
async function doSomething1(){
//最好是将方法返回成promise对象,用resolve,不然些复杂的函数,会导致await没效果
let x = await 'hhh' //这里await修饰的不是一个方法,也不是一个promise对象
return x
}
console.log(doSomething1())
//Promise {} ==> async修饰的函数,就会返回promise对象
doSomething1().then(res => {
console.log(res) //hhh ==> 通过.then获取到promise对象的resolve出来的值
})
另一种情况:
async function doSomething1(){
let x = await fn2() //即使fn2返回的不是promise,也可以用await修饰
return x
}
function fn2(){
return '123456'
}
doSomething1().then(res => {
console.log(res) //123456 ==>因为是用async修饰的函数,所以可以用.then获取到返回的数据
})
1、async修饰的方法返回的是一个promise对象,其 return 返回的值,会成为 .then() 方法回调函数的参数;
2、await修饰的方法如果得到的不是promise对象,也是可以的,得到的是啥就是啥,仍然会有await的阻塞效果(同步)。
function fn1(){
//最好是将方法返回成promise对象,用resolve,不然些复杂的函数,会导致await没效果
return new Promise(resolve=>{
setTimeout(function(){
msg='wait me 3000';
resolve(msg)
},3000);
});
}
async function asyncCall(){
var result=await fn1();
console.log(result);
}
asyncCall();
运行结果:
三秒后,会输出: wait me 3000
这是因为有await将fn1方法改成了同步方法,阻塞了后面的console.log(result),等到执行完fn1中的异步方法后,拿到了resolve的返回值,才去执行下一步。
如上图所示,如果不适用async await将fn1方法转成同步方法,那么因为fn1中的异步操作会在console.log(result)这个同步方法执行完后才执行,也就没有拿到resolve的返回值,自然就会输出undefined
try{
fn()
}
catch(error){
console.error(error);
}
try catch只能捕获【同步方法】的错误,如果fn是个异步方法,就会报错,捕获不到,所以,一般都是对 async await修饰的方法用try catch,因为async await修饰的方法就会变成【同步方法】
看完上面的例子,你现在应该知道,如何把函数转成同步来执行了,接下来用一个例子来说明一下:
async function a () {
return new Promise((resolve, reject) => {
resolve('123456')
})
}
//通过async修饰后的方法,可以用.then来获取返回值
a().then(res => {
console.log(res) // 123456
})
或者:
async function a () {
return '123456'
}
a().then(res => {
console.log(res) //123456
})
通过async修饰后的方法,可以用.then来获取返回值,然后我们就可以在.then中进行下一个方法的调用了,这样既能规定好哪一个方法先执行,哪一个后执行
当然,你也可以用 await,直接把想要的方法转换成同步方法
async a () {
//最好是将方法返回成promise对象,用resolve,不然些复杂的函数,会导致await没效果
return new Promise((resolve, reject) => {
resolve('123456')
})
}
//通过await将方法a()转成同步的,执行完a方法之后,才会往下执行
var result=await a();
console.log(result);
b()
c()
.....
有时候,你设置了一个async方法,然后里面return一个promise对象,然后这个对象里面还要调用一个await方法,那么【eslint规范】会报错提示:promise中不建议使用await,你可以直接利用vscode的错误修复功能,alt+. 在报错行添加一行注释,取消eslint的报错,这样就能正常运行了。