JavaScript không đồng bộ hiện đại với Async và Await

Khám phá cách tiếp cận hiện đại đối với các hàm không đồng bộ trong JavaScript. JavaScript đã phát triển trong một thời gian rất ngắn từ callbacks đến Promises, và kể từ ES2017, JavaScript không đồng bộ thậm chí còn đơn giản hơn với cú pháp async / await

Giới thiệu

JavaScriptphát triển trong một thời gian rất ngắn từ gọi lại đếnlời hứa(ES2015), và kể từES2017JavaScript không đồng bộ thậm chí còn đơn giản hơn với cú pháp async / await.

Các hàm không đồng bộ là sự kết hợp của các lời hứa vàmáy phát điệnvà về cơ bản, chúng là một mức trừu tượng cao hơn so với các lời hứa. Hãy để tôi nhắc lại:async / await được xây dựng dựa trên những lời hứa.

Tại sao async / await được giới thiệu?

Chúng giảm bớt phần biên tập xung quanh các lời hứa và giới hạn “không phá vỡ chuỗi” của các lời hứa chuỗi.

Khi Promises được giới thiệu trong ES2015, chúng nhằm giải quyết vấn đề với mã không đồng bộ và chúng đã làm được, nhưng trong 2 năm tách biệt ES2015 và ES2017, rõ ràng làlời hứa không thể là giải pháp cuối cùng.

Hứa hẹn đã được giới thiệu để giải quyết các nổi tiếngđịa ngục gọi lạivấn đề, nhưng họ đã tự giới thiệu độ phức tạp và độ phức tạp cú pháp.

Chúng là những nguyên thủy tốt để các nhà phát triển có thể sử dụng một cú pháp tốt hơn, vì vậy khi đến thời điểm thích hợp, chúng tôi sẽchức năng không đồng bộ.

Chúng làm cho mã trông giống như đồng bộ, nhưng nó không đồng bộ và không bị chặn đằng sau hậu trường.

Làm thế nào nó hoạt động

Một hàm không đồng bộ trả về một lời hứa, như trong ví dụ này:

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

Khi nào bạn muốngọichức năng này bạn thêm vào trướcawait, vàmã cuộc gọi sẽ dừng cho đến khi lời hứa được giải quyết hoặc bị từ chối. Một lưu ý: chức năng máy khách phải được định nghĩa làasync. Đây là một ví dụ:

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

Một ví dụ nhanh

Đây là một ví dụ đơn giản về async / await được sử dụng để chạy một hàm không đồng bộ:

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’)

Đoạn mã trên sẽ in nội dung sau vào bảng điều khiển của trình duyệt:

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: