Home  >  Article  >  Web Front-end  >  Understand how asynchrony is handled in JavaScript

Understand how asynchrony is handled in JavaScript

青灯夜游
青灯夜游forward
2020-11-20 17:29:059361browse

Understand how asynchrony is handled in JavaScript

In website development, asynchronous events are a link that projects must deal with. Also because of the rise of front-end frameworks, SPA implemented through frameworks has become a standard for quickly building websites. Obtaining data has become an indispensable part; this article will talk about asynchronous processing in JavaScript.

Synchronize? asynchronous?

First of all, of course, we must first understand what synchronization and asynchronous refer to respectively.

These two terms are always confusing for beginners. After all, the literal meaning in Chinese is easy to understand in reverse. From the perspective of information science, synchronization refers to Do things one by one, while asynchronously is when many things are processed together in parallel.

For example, when we go to the bank to handle business, queuing in front of the window is synchronous execution, and getting the number and doing other things first is asynchronous execution; through the characteristics of Event Loop, asynchronous events can be said in JavaScript It’s a piece of cake

So what is the way to handle asynchronous events in JavaScript?

Callback function

The callback function we are most familiar with is the callback function. For example, the event listener registered when the web page interacts with the user needs to receive a callback function; or various functions of other Web APIs such as setTimeout, xhr can also be passed Pass the callback function to trigger at the time requested by the user. Let’s first look at an example of setTimeout:

// callback
function withCallback() {
  console.log('start')
  setTimeout(() => {
    console.log('callback func')
  }, 1000)
  console.log('done')
}withCallback()
// start
// done
// callback func

After setTimeout is executed, when the specified time interval has passed, the callback function will be placed at the end of the queue , and then wait for the event loop to process it.

Note: Because of this mechanism, the time interval set by the developer to setTimeout will not be exactly equal to the time elapsed from execution to triggering. Please be careful when using it. pay attention!

Although callback functions are very common in development, there are also many problems that are difficult to avoid. For example, because functions need to be passed to other functions, it is difficult for developers to control the processing logic in other functions; and because the callback function can only cooperate with try...catch to catch errors, it is difficult to control when an asynchronous error occurs; in addition, There is the most famous "callback hell".

Promise

Fortunately, Promise appeared after ES6, saving developers who were trapped in hell. Its basic usage is also very simple:

function withPromise() {
  return new Promise(resolve => {
    console.log('promise func')
    resolve()
  })
}
withPromise()
  .then(() => console.log('then 1'))
  .then(() => console.log('then 2'))
// promise func
// then 1
// then 2

What was not mentioned when discussing Event Loop before is that in the HTML 5 Web API standard, Event Loop adds a micro task queue, and Promise It is driven by the microtask queue; the triggering time of the microtask queue is when the stack is cleared. The JavaScript engine will first confirm whether there is anything in the microtask queue. If there is anything, it will be executed first and will not be taken from the queue until it is cleared. Pop new tasks onto the stack.

As in the above example, when the function returns a Promise, the JavaScript engine will put the function passed in later into the microtask queue, loop repeatedly, and output the results listed above. The subsequent .then syntax will return a new Promise, and the parameter function will receive the result of the previous Promise.resolve. With this function parameter transfer, developers can pipeline Handle asynchronous events sequentially.

If you add setTimeout to the example, you can more clearly understand the difference between microtasks and general tasks:

function withPromise() {
  return new Promise(resolve => {
    console.log('promise func')
    resolve()
  })
}
withPromise()
  .then(() => console.log('then 1'))
  .then(() => setTimeout(() => console.log('setTimeout'), 0))
  .then(() => console.log('then 2'))
// promise func
// then 1
// then 2 -> 微任务优先执行
// setTimeout

In addition, the callback function mentioned above is difficult to handle Asynchronous errors can also be captured through the .catch syntax.

function withPromise() {
  return new Promise(resolve => {
    console.log('promise func')
    resolve()
  })
}
withPromise()
  .then(() => console.log('then 1'))
  .then(() => { throw new Error('error') })
  .then(() => console.log('then 2'))
  .catch((err) => console.log('catch:', err))
// promise func
// then 1
// catch: error
//   ...error call stack

async await

Since the advent of ES6 Promise, asynchronous code has gradually changed from callback hell to elegant functional pipeline processing, but for those who are not familiar with it, For developers, it just changes from callback hell to Promise hell.

The new async/await is standardized in ES8. Although it is just syntactic sugar for combining Promise and Generator Function, it is passed through async/await Then asynchronous events can be processed with synchronous syntax, just like an old tree blooming new flowers. The writing style is completely different from Promise:

function wait(time, fn) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('wait:', time)
      resolve(fn ? fn() : time)
    }, time)
  })
}
await wait(500, () => console.log('bar'))
console.log('foo')
// wait: 500
// bar
// foo

By setTimeout is packaged into a Promise and then called with the await keyword. You can see that the result will be synchronously executed first bar and then foo , that is, writing asynchronous events into synchronous processing mentioned at the beginning.

Look at another example:

async function withAsyncAwait() {
  for(let i = 0; i < 5; i++) {
    await wait(i*500, () => console.log(i))
  }
}await withAsyncAwait()
// wait: 0
// 0
// wait: 500
// 1
// wait: 1000
// 2
// wait: 1500
// 3
// wait: 2000
// 4

The code implements the withAsyncAwait function, using the for loop and the await keyword Execute the wait function repeatedly; when executed here, the loop will wait for a different number of seconds in sequence before executing the next loop.

When using async/await, since the await keyword can only be executed in async function, be sure to remember to use it at the same time .

In addition, when using loops to process asynchronous events, you need to note that many Array methods provided after ES6 do not support the async/await syntax. If you use forEach# here, ## Replace for, the result will become synchronous execution, and numbers will be printed every 0.5 seconds:

Summary

This article briefly introduces JavaScript handles three ways of asynchronous processing, and uses some simple examples to illustrate the order of code execution; echoing the event loop mentioned earlier, the concept of microtask queue is added to it. Hope it helps you understand synchronous and asynchronous applications.

For more programming-related knowledge, please visit:

Introduction to Programming! !

The above is the detailed content of Understand how asynchrony is handled in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete