JS | async和await

async和await的定义

任何一个名称都是有含义的,先从字面意思来理解.async是"异步"的简写,而await可以认为是async wait的简写,于是我们可以理解:

  • async用于申明一个function是异步的
  • await用于等待一个异步方法执行完成

async起什么作用

这个问题的关键在于,async函数是如何处理它的返回值的!
我们当然希望它可以直接通过return语句返回我们想要的结果,可如果是这样,似乎就没await什么事儿了.所以让我们写段代码来试试,看它到底会返回什么

async function testAsync() {
  return 'hello';
}
const result = testAsync();
console.log(result)  // promise{<resolved>:'hello'};

上面代码显示,最后输出的是一个promise对象.所以 async函数返回的是一个Promise对象,从 文档 中也可以得到这个信息.async函数(包括函数语句,函数表达式,Lambda表达式)会返回一个Promise对象.如果函数体中return一个直接量,async会把这个直接量通过Promise.resolve()封装成一个Promise对象.

async函数返回的是一个Promise对象,所以在最外层不能用await获取其返回值的情况下,我们当然应该用原来的方式:then()链来处理这个Promise对象,就像这样

testAsync().then( v => {
  console.log(v) // hello
})

现在回过头来想下,如果async函数没有返回值,又改如何?很容易想到,它会返回
Promise.resolve(undefined)

联想一下Promise的特点 --- 无等待,所以在没有await的情况下执行async函数,它会立即执行,返回一个Promise对象,并且,绝不会阻塞后面的进程,这和普通返回Promise对象的函数并无不同

那么下一个关键点就在于await关键字了

await到底在等啥

一般来说,都认为await是在等待一个async函数完成.不过按照语法说明,await等待的是一个表达式,这个表达式的计算结果是一个Promise对象或其他说明值(换句话说,就是没有限定)

因为async返回的是一个Promise对象,所以await可以用于等待一个async函数的返回值---这也可以说是await在等async函数,但要清楚,它等的其实是一个返回值.注意await不仅仅用于等待Promise对象,它可以等待任意表达式的返回值,所以,await后面实际是可以接普通函数调用或者直接量的.所以下面这个示例是可以正确运行的

async function getSomething() {
  return 'getSomething';
}

async function testAsync() {
  return Promise.resolve('hello');
}

async function test() {
  const v1 = getSomething();
  const v2 = testAsync();
  console.log(v1,v2)
}

test();

await等到了要等的,然后呢

await等到了它要等的东西,一个Promise对象,或者其他值,然后呢?我不得不先说,await是一个运算符,用于组成表达式,await表达式的运算结果取决于它等的东西

如果它等到的不是一个Promise对象,那await表达式的运算结果就是它等到的东西

如果它等到的是一个Promise对象,那await就忙起来了,await会阻塞后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果

image.png

async和await帮我们干了啥

作个简单的比较

上面已经说明了,async会将后面的函数()的返回值封装成一个Promise,而await会等待这个Promise完成,并将resolve的值返回出来

现在举例,用setTimeout模拟耗时的异步操作,先来看看不用async和await会怎么写

function takelongTime() {
  return new Promise( resolve => {
    setTimeout(() = > {
      console.log('loong_time_value')
    },1000)
  })
}

takeLongTime().then( v => {
  console.log(v)
})

现在改用async和await以后, 会是这样:

function takeLongTime() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('long_time_value');
    })  
  })
}

async function test() {
  const v = await takeLongTime();
  console.log(v);
}

test();

这里takeLongTime函数没有用async申明.实际上,takeLongTime本身就是返回的Promise对象,加不加async结果都一样.

上面两种方式,都是对异步调用的处理(实际都是对promise对象的处理)差别并不明显,甚至使用async和await,代码看起来更多,那么它的优势到底在哪里?

async和await的优势在于处理then链

单一的Promise链并不能发现async和await的优势,它的优势在于处理由多个Promise组成的then链

假设一个业务,分多个步骤完成,每一个步骤依赖上一个步骤的结果,我们依然用setTimeout来模拟异步操作

/**
  *传入参数n,表示这个函数需要执行的时间(毫秒)
  *得到的结果是n + 200,这个值将用于下一步骤
  */
function takeLongTime() {
  return new Promise(resolve => {
    setTimeout(() => resolve(n + 200),n)
  })
}
function stemp1() {
  console.log(`stemp1 with ${n}`)
  return takeLongTime(n);
}
function stemp2() {
  console.log(`stemp2 with ${n}`)
  return takeLongTime(n);
}
function stemp3() {
  console.log(`stemp3 with ${n}`)
  return takeLongTime(n);
}

现在用promise方法来实现这三个步骤的处理

function doIt() {
  console.time('doIt');
  const time1 = 300;
  stemp1(time1)
         .then(time2 => stemp2(time2))
         .then(time3 => stemp3(time3))
         .then(result => {
            console.log(`result is ${result}`)
            console.timeEnd('doIt')
          }) 
}
doIt();
输出结果 result 是 step3() 的参数 700 + 200 = 900。doIt() 顺序执行了三个步骤,
一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果基本一致。

下面用async和await来实现

async function doIt() {
  console.log('doIt');
  const time1 = 300;
  const time2 = await stemp1(time1);
  const time3 = await stemp2(time2);
  const result = await stemp3(time3);
  console.log(`result is ${result}`)
  console.timeEnd('doIt');
}

结果和之前的promsise实现是一致的,这样做的好处就是代码清晰了很多,几乎跟同步代码是一样的
原文摘自 《理解JavaScript 的 async/await》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容