具有Async和Await的现代异步JavaScript

探索JavaScript中异步函数的现代方法。 JavaScript从回调到Promises的发展时间很短,而且由于ES2017异步JavaScript使用async / await语法甚至更简单

介绍

JavaScript在很短的时间内从回调发展到了诺言(ES2015),以及ES2017使用async / await语法,异步JavaScript甚至更简单。

异步功能是Promise和发电机,基本上,它们是对Promise的更高层次的抽象。让我重复一遍:异步/等待是基于promise的

为什么引入异步/等待?

它们减少了兑现承诺的样板,并降低了兑现承诺的“不破坏链条”的局限性。

在ES2015中引入Promises时,它们旨在解决异步代码的问题,并且确实做到了,但是在将ES2015和ES2017分开的两年中,很明显,承诺不可能是最终的解决方案

介绍了解决著名的承诺回调地狱问题,但是他们自己引入了复杂性以及语法复杂性。

它们是很好的原语,可以向开发人员公开更好的语法,因此,当时间合适时,我们可以异步功能

它们使代码看起来像是同步的,但在后台却是异步且无阻塞的。

怎么运行的

异步函数返回一个Promise,例如以下示例:

const doSomethingAsync = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve('I did something'), 3000)
  })
}

当你想称呼此功能是您最喜欢的await, 和调用代码将停止,直到承诺被解决或被拒绝为止。一个警告:客户端功能必须定义为async。这是一个例子:

const doSomething = async () => {
  console.log(await doSomethingAsync())
}

一个简单的例子

这是用于异步运行函数的async / await的简单示例:

const doSomethingAsync = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve('I did something'), 3000)
  })
}

const doSomething = async () => { console.log(await doSomethingAsync()) }

console.log(‘Before’) doSomething() console.log(‘After’)

上面的代码会将以下内容打印到浏览器控制台:

Before
After
I did something //after 3s

Promise all the things

Prepending the async keyword to any function means that the function will return a promise.

Even if it’s not doing so explicitly, it will internally make it return a promise.

This is why this code is valid:

const aFunction = async () => {
  return 'test'
}

aFunction().then(alert) // This will alert ‘test’

and it’s the same as:

const aFunction = async () => {
  return Promise.resolve('test')
}

aFunction().then(alert) // This will alert ‘test’

The code is much simpler to read

As you can see in the example above, our code looks very simple. Compare it to code using plain promises, with chaining and callback functions.

And this is a very simple example, the major benefits will arise when the code is much more complex.

For example here’s how you would get a JSON resource, and parse it, using promises:

const getFirstUserData = () => {
  return fetch('/users.json') // get users list
    .then(response => response.json()) // parse JSON
    .then(users => users[0]) // pick first user
    .then(user => fetch(`/users/${user.name}`)) // get user data
    .then(userResponse => userResponse.json()) // parse JSON
}

getFirstUserData()

And here is the same functionality provided using await/async:

const getFirstUserData = async () => {
  const response = await fetch('/users.json') // get users list
  const users = await response.json() // parse JSON
  const user = users[0] // pick first user
  const userResponse = await fetch(`/users/${user.name}`) // get user data
  const userData = await userResponse.json() // parse JSON
  return userData
}

getFirstUserData()

Multiple async functions in series

Async functions can be chained very easily, and the syntax is much more readable than with plain promises:

const promiseToDoSomething = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve('I did something'), 10000)
  })
}

const watchOverSomeoneDoingSomething = async () => { const something = await promiseToDoSomething() return something + ’ and I watched’ }

const watchOverSomeoneWatchingSomeoneDoingSomething = async () => { const something = await watchOverSomeoneDoingSomething() return something + ’ and I watched as well’ }

watchOverSomeoneWatchingSomeoneDoingSomething().then(res => { console.log(res) })

Will print:

I did something and I watched and I watched as well

Easier debugging

Debugging promises is hard because the debugger will not step over asynchronous code.

Async/await makes this very easy because to the compiler it’s just like synchronous code.


More js tutorials: