关于async和await

    技术2022-07-10  149

    JavaScript中的async/await是AsyncFunction特性中的关键字。(读者可自行查阅改链接中内容)

    async定义的异步函数,通过使用 await,让异步函数的表现更像是同步函数。不用再层层回调。它是Generator函数的语法糖。其中async来声明该函数里有异步操作。await表示紧跟在后面的表达式需要等待结果

    与Generator函数比优点:

    内置执行器。Generator函数的执行必须依靠执行器,而 Aysnc函数自带执行器,调用方式跟普通函数的调用一样‘更好的语义。async和 await相较于 *和 yield更加语义化更广的适用性。co 模块约定,yield命令后面只能是 Thunk 函数或 Promise对象。而 async函数的 await命令后面则可以是 Promise或者 原始类型的值(Number,string,boolean,但这时等同于同步操作)返回值是 Promise。async函数返回值是 Promise 对象,比 Generator函数返回的 Iterator 对象方便,可以直接使用 then()方法进行调用

    如果你还不了解Generator函数,你可以查阅下面:

    阮一峰 ES6入门:Generator相关知识

    先看几个demo:

    1、之前不用async的异步Promise操作

    定义个获取用户信息的函数:

    function getUserInfo() { return new Promise((resolve, reject) => { fetch('http://abc.com') .then(res => { reslove(res) }, error => { reject(error) }) }) } function showUserInfo() { getUserInfo() .then(res => { //... }, error => { //.... }) }

    2、使用Generator 方式

    function* showUserInfo() { const user = yield getUserInfo() return user } const g = showUserInfo() cosnt res = g.next().value() result.then(res => { //.. }, error => { //.. })

    Generator的方式解决了 Promise的一些问题,流程更加直观、语义化。但是 Generator的问题在于,函数的执行需要依靠执行器,每次都需要通过 g.next()的方式去执行。

    3、使用async/await

    async function showUserInfo() { const res = await getUserInfo(); return res } showUserInfo(). then(res => { //.. })

    看到这里你可能还有点一脸懵逼,别着急,接着往下看。

    4、语法

    async函数内部返回一个Promise对象。其在内部返回(return)的值会成为then方法的参数。

    async function f() { return 'hello world' }; f().then( (v) => console.log(v)) // hello world

    如果async函数内部抛出异常,则返回的Promise状态会变为reject状态。抛出的错误会被catch方法捕捉到。

    async function e(){ throw new Error('error'); } e().then(v => console.log(v)) .catch( e => console.log(e));

    需要注意的是:async返回的Promise对象,必须等到内部所有的await命令的Promise对象执行完毕,才会发生状态改变。也就是说只有当async内部的异步操作都成功执行完,才会执行then里的方法

    const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout)); async function f(){ await delay(1000); await delay(2000); await delay(3000); return 'done'; } f().then(v => console.log(v)); // 等待6s后才输出 'done'

    正常情况下,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值(如果没有返回值,那么默认返回值将是undefined)

    async function f() { return await 1 }; f().then( (v) => console.log(v)) // 1

    如果此时返回的 reject的状态,就会被catch捕获。

    async function foo() { return Promise.reject(123) } foo().then().catch(e => console.log(e)) //控制台打印出 '123'

    5、async函数的错误处理

    let a; async function f() { await Promise.reject('error'); a = await 1; // 这段 await 并没有执行 } f().then(v => console.log(a)).catch(err => console.log(err))

    只要async函数中的一个 await出现reject状态,那么后面的await就不会再执行。

    此时错误处理使用try/catch来处理。

    let a; async functoin f() { try { await Promise.reject('error') } catch (err) { console.log(err) } a = await 1; return a } f().then(v => console.log(a)).catch(err => console.log(err))

    如果有多个await,可以都放在try/catch中。

    6、一些代码来加强认知

    async function asyncFun() { return '我后执行' } asyncFun().then(v => console.log(v)) console.log('我先执行');

    这段代码会先打印出我先执行,再打印我后执行.

    因为声明了asyncFun为异步函数。该函数虽然先执行了,但是不会阻断后面代码的执行。同步代码先执行。

    注意对比下面代码,理解执行顺序。

    const timeOut = timeOut => { return new Promise(resolve => setTimeout(resolve, timeOut)) } async function timeFun() { await timeOut(1000) await timeOut(2000) return 'end..' } timeFun().then(v => console.log(v)) //打印结果 [Running] node "c:\lhch\work\Projects\own\vue\async.js" end.. [Done] exited with code=0 in 3.093 seconds //可以看出 在3s后打印出了end.. ,这是使用了await的效果

    7、async里的函数必须将结果return

    async里必须将结果return,如果不返回结果,那么不管是resolve或者reject状态,其值都是undefined。这里建议使用箭头函数。

    这是正确的写法,控制台会打印errrrr

    async function errFun() { return Promise.reject('errrrr') } errFun().then().catch(v => console.log(v))

    错误的写法:

    async function errFun() { Promise.reject('errrrr') }

    这里执行errFun控制台会直接报错。

    需要深入理解的: 只要async返回的值不是异常或者reject,就会判定成功。在async函数里,可以return各种类型的值。

    只有出现如下情况的时候,才会判定失败reject:

    内部使用未声明的变量或者函数内部直接抛出错误(throw new Error)或者返回reject状态(retrun Promise.reject)函数方法执行出错 async function c() { return '接受到了吧' } c().then(v => console.log(v))

    上面代码控制台会打印出 '接受到了吧',同时显示://Promise { <resolved>: undefined }

    为什么 resolved的是undefined呢,因为then后是执行的console语句,这里没有返回值。

    一个小总结:

    是一种编写异步代码的新方法。之前异步代码的方案是callback和promise。建立在 promise的基础上,与promise一样也是非阻塞的。async/await让异步代码看起来、表现起来更像同步代码。这正是其魅力(作用)所在。

    建议您读此文的时候,自己手敲代码,加深理解.

    如果此文帮到了你,你可以捐赠,以示鼓励。

    Processed: 0.009, SQL: 9