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:
定义个获取用户信息的函数:
function getUserInfo() { return new Promise((resolve, reject) => { fetch('http://abc.com') .then(res => { reslove(res) }, error => { reject(error) }) }) } function showUserInfo() { getUserInfo() .then(res => { //... }, error => { //.... }) }Generator的方式解决了 Promise的一些问题,流程更加直观、语义化。但是 Generator的问题在于,函数的执行需要依靠执行器,每次都需要通过 g.next()的方式去执行。
看到这里你可能还有点一脸懵逼,别着急,接着往下看。
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'只要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中。
这段代码会先打印出我先执行,再打印我后执行.
因为声明了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的效果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让异步代码看起来、表现起来更像同步代码。这正是其魅力(作用)所在。建议您读此文的时候,自己手敲代码,加深理解.