首先,要明白异步跟同步,参考下方博客的案例介绍:async/await让异步操作同步执行的方法详解 - dreamw - 博客园 ()/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,仍然会被当作异步方法,要等到同步方法执行完才会执行它
注意:利用setTimeout=>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和await
async:它修饰的方法,返回的数据就会是个promise对象(可单独使用)
await:意思是等待执行完它修饰的方法,再往下执行,它会阻塞后面的代码,也就是同步
await 如果得到的是 Promise 对象,则得到其 resolve值需要配合async使用
例子1:
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()
例子2:
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值
例子3:
async function doSomething1(){//最好是将方法返回成promise对象,用resolve,不然些复杂的函数,会导致await没效果let x = await 'hhh' //这里await修饰的不是一个方法,也不是一个promise对象return x }console.log(doSomething1()) //Promise {<pending>} ==> 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的阻塞效果(同步)。
例子4:
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 catch只能用来捕获【同步函数】,不能用来捕获【异步函数】
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的报错,这样就能正常运行了。