异步神器Async-await介绍与填坑

async/await 是ES7中被提实现异步操作的技术,相对比较新,好在babel爸爸已对它支持,我们可以欢快的对它进行使用。了解async/await前要求对Promise有一定的理解,或可阅读 深入理解 Promise 一文。盗图

# async - 定义异步函数

async 译:异步,是 Generator 函数的语法糖。该函数会返回一个promise对象,可以使用then方法添加回调函数,如果在函数内直接 return,Async会通过Promise.resolve()将其封装成Promise()对象,也可以通过.then添加回调函数

async function pms() {
  return 'abc'
}
console.log(pms())  // [object Promise] { ... }

  以上方法执行返回了一个promise对象,其执行等效于

async function pms() {
  return new Promise((resolve, reject) => {
    resolve('abc')
  })
}

  在没有配合await时,我们可以调用promise的.then方法得到执行结果。当然也会有.catch方法

pms().then(res => {
  console.log(res)  // 'abc'
}).catch(e => {
  console.log('错误')
})

# await - 暂停异步函数的执行

await,即:async wait,旨在等待异步执行结束,使用于async函数内部。异步未执行结束,阻塞当前代码。嗯哼?阻塞!!!

  与线程阻塞不同的是,await 的阻塞发生在 async 函数内部,可以理解为一个异步的阻塞。跟在await后的JS表达式,可以等待很多类型的事件,但初衷是用于等待Promise对象。如果await的对象是promise对象,则阻塞异步函数代码执行等待promise的resolve状态,如果是同步执行的表达式则立即执行。

# async/await的使用

function asyncFunc(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {  // 用setTimeout模拟异步
      resolve('async result')
    }, time)
  })
}

function normalFunc() {
  console.log('normal result')
}

async function awaitDemo() {
  await normalFunc()  // 执行立即打印 normal result
  const res = await asyncFunc(1000)
  console.log(res) // 执行1s后打印 ‘async result’
}

awaitDemo() // 执行 

  以上的例子比较常规,再看看下面这个例子

async function func() {
  console.log('123')
}
async function run() {
  const res = await func()
  console.log(res)  // 123
}
run()

  该例子中,func看似一个普通函数,但经async定义后,会返回一个promise对象,此时的await等待的就是该promise对象的resolve参数,即123
  对比上一个例子中的normalFunc,主要有两个理解点
(1)增加了async的普通函数变成了一个异步函数,await等待的对象为promise对象,返回resolve参数
(2)await可以等待任何东西,如果等待的是普通内容,则直接返回该内容

# 【填坑1】异常处理

  细心的你应该已经发现,await 返回的是promise的resolve参数,但对于catch却没有实际的处理。那当我们的请求发生异常时,该怎么办?答案是使用try-catch,在Promise中的.catch()分支会流入catch

function asyncFunc(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {  // 用setTimeout模拟异步
      reject('promise reject')
    }, time)
  })
}
// 为了处理Promise.reject 的情况我们应该将代码块用 try catch 捕获一下
async function awaitDemo() {
  try {
    const res = await asyncFunc(1000)
    console.log(res)
  } catch (err) {
    console.log(err.message || 'Uncatch Error')
  }
}

awaitDemo()  // 如果没有使用try-catch,执行会报错

# 【填坑2】并行请求

  对于一个真实的业务需求,通常会有多个异步请求需要同时执行,如获取左侧目录树,和登录账户的用户信息等。因await遇到异步会阻塞,当一个async函数内有多个异步函数需要调用时,就会出现相互等待的现象。天哪,“异步” 变成了 “同步”了,这不是我们所希望的

function asyncFunc() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('request done')
    })
  })
}
async function bugDemo() {
  await asyncFunc()
  await asyncFunc()
  await asyncFunc()
  console.log('finish')
}

  以上代码正常执行了,没有报出异常,但仔细观察控制台 timeline 可以发现,三个函数是同步顺序执行的,其罪魁祸首就是await的等待机制。那怎么解决这个问题?

  其实async-await 只是promise的语法糖,但其并不能代替Promise,从对异常的处理上就可以看出,还需要引入try-catch ,本问题是另一个体现。解决办法需要使用promise的.all()

promise.all( iterable ),当所有请求都为resolve时,返回resolve状态

async function correctDemo() {
  const f1 = asyncFunc()
  const f2 = asyncFunc()
  const f3 = asyncFunc()
  await Promise.all([f1, f2, f3]);
  console.log('finish')
}

# 【填坑3】await必须在async的上下文中

await 并不只是使用在async 函数中即可,还必须在asyn函数的上下文中

// 虽在async函数里使用,但在forEach上下文中,异常
async function errorDemo() {
    [1, 2, 3, 4, 5].forEach(item => {
        await item;
    });
}
errorDemo() // SyntaxError: await is only valid in async function
// await 必须在async函数的上下文中
async function correctDemo() {
    let arr = [1, 2, 3, 4, 5];
    for (let i = 0; i < arr.length; i ++) {
        await arr[i];
    }
}

# refs

async函数介绍
异步神器Async

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