资讯专栏INFORMATION COLUMN

使用ES2017 async/await函数的注意点

libxd / 2006人阅读

摘要:正常函数异常函数注意当返回值本身就是一个对象时,函数的并不会对返回值进行二次包装。总是按顺序执行使用函数之前,我们还得搞清楚它的运行机制。因此在函数中的并不会挂起整个函数的执行。

随着node 7.6.0正式实装async/await函数,js的异步编程变的比以往更加容易。但是,在我们全面投入async/await的怀抱之前,有必要对这个特性做一些细致的了解。

书写形式

基本上,任何一个函数都可以成为async函数,以下都是合法的书写形式:

函数声明
async function foo () {}

函数表达式
const foo = async function () {}

方法定义
const obj = { async foo () {} }

箭头函数
async () => {}

async函数总是返回Promise

即使返回值只是一个primitive值,async函数也会通过return自动将返回值包装成一个Promise对象返回。
因此,下面两组函数是等价的。

正常 (Fulfill)
// async函数
async function foo () {
  return "a"
}

// Promise
function foo () {
  return Promise.resolve("a")
}
异常 (Reject)
// async函数
async function foo () {
  throw new Error("error")
}

// Promise
function foo () {
  return Promise.reject(new Error("error"))
}

注意:当返回值本身就是一个Promise对象时,async函数的return并不会对返回值进行二次包装。

await总是按顺序执行

使用async函数之前,我们还得搞清楚它的运行机制。尤其是在执行顺序上,完全用同步的思维也许并不适用于async函数。

考虑下面的代码

function asyncGet (x) {
  return new Promise(resolve => setTimeout(() => {
    console.log("a")
    resolve(x)
  }, 500))
}

async function test () {
  console.log("b")
  const x = 3 + 5
  console.log(x)

  const a = await asyncGet(1)
  console.log(a)

  const b = await asyncGet(2)
  console.log(b)

  console.log("c")  
  return a + b
}

const now = Date.now()
console.log("d")
test().then(x => {
  console.log(x)
  console.log(`elapsed: ${Date.now() - now}`)
})
console.log("f")

async函数和普通函数一样按顺序执行,同时,在执行到await语句时,返回一个Promise对象

await可以理解为将async函数挂起,直到等待的Promise被fulfill或者reject,再继续执行之后的代码

async函数的返回值和普通Promise没有区别

因此,上面代码输出应该是

d
b
8
f
a
1
a
2
c
3
elapsed: 1010

注意 d 和 f 中间的输出

让我们再来看一个混合了Promise的版本。

function asyncGet (x) {
  return new Promise(resolve => setTimeout(() => {
    console.log("a")
    resolve(x)
  }, 500))
}

async function test () {
  console.log("b")
  const x = 3 + 5
  console.log(x)

  const [a, b] = await Promise.all([
    asyncGet(1),
    asyncGet(2)
  ])

  console.log("c")  
  return a + b
}

const now = Date.now()
console.log("d")
test().then(x => {
  console.log(x)
  console.log(`elapsed: ${Date.now() - now}`)
})
console.log("f")

输出结果

d
b
8
f
a
a
c
3
elapsed: 509

注意到elapsed的差别了吗?这就是为什么我们说await总是顺序执行的。不同的await之间无法并行执行,想要真正的完全异步还得借助类似Promise.all这样的方法。

async函数和callback

await只能能影响直接包裹它的async函数。因此在callback函数中的await并不会挂起整个async函数的执行。

一种常见的错误

async function getAll (vals) {
  return vals.map(v => await asyncGet(v))
}

这段代码有语法错误,await并不在async函数内部。如果给map的callback加上async呢?

async function getAll (vals) {
  return vals.map(async v => await asyncGet(v))
}

这段代码虽然能执行,但还有两个问题。

返回一个Promise对象的数组,并不是我们期待的value数组

await只会暂停map的callback,因此map完成时,不能保证asyncGet也全部完成

正确的写法还得借助Promise.all

async function getAll (vals) {
  return Promise.all(vals.map(v => asyncGet(v)))
}
总结

从上我们可以看出,Promiseasync函数的基础,想要愉快的使用async函数,必须对Promise有比较深入的理解。甚至一些常见的任务,仅仅依靠async函数无法实现。
希望大家看完本文后能对async函数有个更全面的认识,这样使用起来才会更加顺手。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86812.html

相关文章

  • 理解ES7中async函数

    摘要:什么是标准引入了函数,使得异步操作变得更加方便。顾名思义是异步的意思,用于声明一个函数是异步的。的作用正常情况下,命令后面是一个对象。表示函数等待返回结果了,再继续执行。上面便是一种错误用法,并没有在函数执行上下文中,而是在的回调函数中。 什么是Async、await ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async顾名思义是异步的意思,用于声明一个函数...

    curried 评论0 收藏0
  • ES2017异步函数现已正式可用

    摘要:标准已于年月份正式定稿了,并广泛支持最新的特性异步函数。为了领会,我们需要回到普通回调函数中进一步学习。从此编写回调函数不再那么痛苦。回调是一个函数,可以将结果传递给函数并在该函数内进行调用,以便作为事件的响应。 ES2017标准已于2017年6月份正式定稿了,并广泛支持最新的特性:异步函数。如果你曾经被异步 JavaScript 的逻辑困扰,这么新函数正是为你设计的。 异步函数或多或...

    android_c 评论0 收藏0
  • 前后分离模型之封装 Api 调用

    摘要:和异步处理调用访问数据采用的方式,这是一个异步过程,异步过程最基本的处理方式是事件或回调,其实这两种处理方式实现原理差不多,都需要在调用异步过程的时候传入一个在异步过程结束的时候调用的接口。 Ajax 和异步处理 调用 API 访问数据采用的 Ajax 方式,这是一个异步过程,异步过程最基本的处理方式是事件或回调,其实这两种处理方式实现原理差不多,都需要在调用异步过程的时候传入一个在异...

    trilever 评论0 收藏0
  • ECMAScript 2016,2017和2018中新增功能示例

    摘要:,和中新增功能的示例原文链接翻译链接始终紧跟的最新功能是很难的,更难的是找到有用的代码示例。和其他双字节字符上的和和其它双字节字符串使用的多字节表示。所以和可能无法按照预期的工作。提醒展开运算符用于等号的右侧,解构运算符用于等号的左侧。 ECMAScript 2016,2017和2018中新增功能的示例 原文链接: medium.freecodecamp.org翻译链接:https:/...

    _Dreams 评论0 收藏0
  • asyncawait详解

    摘要:异步函数是和的组合,基本上,它们是对的更高级别的抽象。引入的原因它们降低了对一些固定语法样板的要求,打破了链式不能切断链式的限制。引入来解决著名的回调地狱问题,但是因为他们自身的复杂性,引入了更复杂的语法。 1、简介 需先了解 Promise 【链接地址】 JavaScript 中的异步函数方法。 JavaScript 在很短的时间内从回调演变为 Promises ,从 ES2...

    Simon_Zhou 评论0 收藏0

发表评论

0条评论

libxd

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<