具有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: