Before introducing front-end macro and micro tasks, let’s list a problem and look at it together.

console.log('1')
setTimeout(() => {
  console.log('2')
})
new Promise((resolve, rejects) => {
  console.log('3')
  resolve()
}).then(() => {
  console.log('4')
})
console.log(5)Copy the code

You can come up with your own answer and run the results to see if they are consistent with what you think.

1. Basic concepts

Here are some of the basics of JavaScript

  1. As for the code execution environment, when JavaScript code is executed, the engine will create the execution environment of the current code block. When using variables, only the variables of the current environment and external environment variables containing the current execution environment can be found. The global environment is the outermost execution environment.
  2. JavaScript is single-threaded.
  3. JavaScript uses an event loop mechanism to handle asynchronous operations.

2. Macro task, micro task and event loop mechanism

Those of you who know about event loops know that in event loops, asynchronous events are not placed on the current task execution queue, but are suspended and placed on another callback queue. After the current task queue completes, the JavaScript engine goes back to check if there are any pending tasks in the callback queue, adds the first task to the queue, and repeats the process over and over again.

Both macro and micro tasks perform asynchronous operations after the execution queue completes, so it appears that both macro and micro tasks are placed in callback queues.

Is it really so?

Definitely not. If this were true, then there would be no difference in meaning between macro tasks and micro tasks.

3. Macro versus micro tasks

First of all, we must insist that macro tasks and micro tasks are absolutely different in meaning.

Take a look at the actions that can trigger a macro task in the browser environment (other environments differ) :

  1. I/O operations
  2. setTimeout

  3. setInterval

  4. RequestAnimationFrame (controversy, discussed later)

Take setTimeout for example. Since JavaScript is single-threaded, the timing of setTimeout must not be done by JavaScript, otherwise it will block code execution.

So who does this operation? It’s the host environment. In the case of the browser, JavaScript tells the browser “Hey boy! Here is a timer, you help me watch the point, when the point you tell me “. At this point, the browser performs a timing operation, and when the timing is complete, the setTimeout callback is placed in the callback queue of the JavaScript event loop. This allows JavaScript to handle the callback in subsequent executions.

Let’s take a look at the four points listed above that trigger macro tasks, all browser-dependent!

So, my personal understanding is that macro tasks are callbacks generated by JavaScript and the host environment, and tasks that need to be handled by the host environment and are put into the callback queue are macro tasks.

The operations to trigger the microtask in the browser are as follows:

  1. Promise
  2. MutationObserver

Both of these operations can also produce asynchronous operations, so why not the same as macro tasks? This brings us to another queue for the event loop — the job queue (microtask queue).

To better understand job queues, we call the process from start to finish of the execution queue a tick. The first event of the callback queue is executed in the next tick, and the second event is executed in the next tick. Do this in turn.

The job queue is located at the end of the current tick. Microtasks added in the current tick are not carried over to the next tick, but are triggered at the end of the tick.

Perform a microtask checkpoint. Perform a microtask checkpoint. Perform a microtask checkpoint This operation checks if there are any microtasks in the job queue. If there are, the job queue will continue to execute as well, and the execution queue will be empty after completion.

Therefore, it is safe to say that microtasks generated by the same execution queue will always be executed before macro tasks.

So, to answer the question raised at the beginning of point 3, what is the difference between macro tasks and micro tasks?

A macro task is a callback queue that performs asynchronous operations with the assistance of the host environment, while a microtask is something that tells the Javascript engine to execute our code as soon as possible after processing the current execution queue before the macro task executes.

4. About requestAnimationFrame

I originally defined requestAnimationFrame as a macro task because I used the following code when testing requestAnimationFrame

const testElement = document.getElementById('testElement')
setTimeout(() => {
  console.log(performance.now(), 'settimeout')
}, 0)
requestAnimationFrame(() => {
  console.log(performance.now(),
 'requestAnimationFrame')
})
var observer = new MutationObserver(() => {
  console.log('MutationObserver')}); observer.observe(testElement, {
 childList: true 
})
const div = document.createElement('div')testElement.appendChild(div)
new Promise(resolve => {
  console.log('promise')  resolve()
}).then(() => console.log('then'))
console.log(performance.now(), 'global')Copy the code

The output varies in the browser, with two results after multiple runs

The first is:



Another is:



I originally included requestAnimationFrame in the macro task because it is mostly executed after the setTimeout callback. RequestAnimationFrame and setTimeout are pressed into the callback at different times, resulting in inconsistent callback times.

However, this forcible explanation is still untenable. As an aspiring youth who is determined to become an excellent Programer, we still need to find evidence. — ____ is the south wind

After looking at the spec, I found that the browser rendering process is included in an event loop tick, and the requestAnimationFrame is triggered before the browser redraws. The MDN document reads as follows:

window.requestAnimationFrame()Tell the browser that you want to execute an animation and ask the browser to call the specified callback to update the animation before the next redraw. This method takes as an argument a callback function that is executed before the browser’s next redraw

Therefore, requestAnimationFrame callback timing is also in the current tick, so it is not a macro task, but it is not a micro task, after the micro task.



Of course, if there is a big guy can give advice on this question, welcome to leave a message in the comment section. / Manual flower scattering/manual flower scattering

5. To summarize

Microtasks and macro tasks are the knowledge I came across when I was dealing with a ladybird. After finishing this article, I feel like I have a deeper understanding of JavaScript event loops. Also hope to read this document you can produce help, ha ha.

“Any application that can be written in JavaScript will eventually be written in JavaScript” — Atwood’s Law

Attached to the supplementary

  1. Macro tasks in Node environment:
    1. I/O operations
    2. setTimeout
    3. setInterval
    4. setImmediate
  2. Microtasks in Node environment:
    1. Promise
    2. process.nextTick

  3. By adding the while loop to the delay, you can get a clearer feel for the event loop:
console.log('1')
setTimeout(() => {
  console.log('2')
})
new Promise((resolve, rejects) => {
  console.log('3')
  resolve()
}).then(() => {
  let i = 0
  while(i < 1000000000) {
    i++
  }
  console.log('4')})let i = 0
while(i < 1000000000) {
  i++
}
console.log(5)Copy the code