A gold lieutenant decided to switch careers

I am a gold lieutenant.

Our trade originated in The Three Kingdoms period at the end of the Eastern Han Dynasty. In order to make up for the lack of pay, Cao Cao set up the ranks such as Fachuang Commander, mojin lieutenant, specializing in robbing tombs to get money, pay.

After Cao Cao, the tomb raiders were independent, and there was no division between their peers. They were all the tomb raiders who touched gold.

Thanks to the grave-robbing novels of recent years, more and more people are learning about our business. But these novels are inaccurate, often mysterious and exaggerated in order to attract attention.

Touch gold danger, a little attention will be doomed. In fact, unlike in the novels, where the hero’s halo is used to survive, we have a rigorous workflow.

High risk, uncertain returns. As time goes on, there are fewer and fewer practitioners. I recently decided to switch to the current field.

In order to prevent the loss of this ancestral skill, here I will talk to you about how our line of work.

Why change careers, you ask? Hey, don’t tell me, our line of work is exactly like the way a browser works, so there’s no pressure to learn.

Safety first

Safety comes first.

Our fault tolerance rate in this business is so low, if it’s any worse, it’s a dog belt. So every step after the grave, we have to be very careful, according to the rules.

The tomb is dark and the secret passageways are intricate. The most important thing is to map in time.

Every time over a wick incense, need to pass this period of time through the tunnel, encountered all the organs drawn down, this is called mapping.

The time before drawing is used for work.

To do things

So what exactly do we do? Such as pathfinding, treasure hunting, measuring organs…

If you want to test the mechanism, you have to stop pathfinding. If you want to find treasure, you can’t test the mechanism. In short, do one thing at a time.

Getting out alive is important, but you can’t go home empty-handed.

Our ancestors have long set priorities for things to do, ensuring that the “important things” get done first while ensuring that other things do not get left undone.

Work itself is also very exquisite, every time after finishing there may be some trivial follow-up work. These tasks need to be completed before the next task.

Take the test mechanism for example, when the test after the mechanism also need to check the equipment, so as not to use the next time out of what bad times.

Like checking the ropes, checking the flashlight…

If things are done quickly, a joss stick time can actually do a lot of things.

For example, the time of the joss stick was done in turn:

  • Testing authority

  • Some trivial work after testing the organ

  • scout

  • drawing

So, the work flow after the tomb is as follows:

Complete one or more tasks according to one wick incense cycle and finish the drawing.

Then the next joss stick cycle begins.

According to this process operation, not to say foolproof, that is also very secure.

The bad thing is that some colleagues are too greedy, like this:

If you spend too much time on a task, you won’t have time to draw!

Map missing a piece, where there is a mechanism, where there is less marked, all kinds of risks are self-evident!

After all, this line is too fight life, fortunately, I timely switch to the front end, let me from the browser Angle to interpret it.

A frame in the browser

The typical browser refresh rate is 60 Hz, which means 60 refreshes per second.

1000ms / 60hz = 16.6
Copy the code

The browser renders a frame every 16.6ms, or 16.6ms.

During this time, I will do two things: Task and render.

A task is called a macro task, just like what we do after we go to the grave.

Including setTimeout, setInterval, setImmediate, postMessage, requestAnimationFrame, I/O, DOM events, etc.

Render refers to render a page.

eventLoop

Tasks are divided into different task queues by priority. It’s like “priorities.”

For example, in order to respond to user interactions in a timely manner, the browser assigns 3/4 priority to the Task queue where Mouse and Key events reside.

This allows you to respond to user interactions in a timely manner without failing to execute tasks in other task queues.

The dotted part of the work to do is:

  1. Insert new tasks into different task queues.

  2. Select a task from a task queue by priority.

This is called an eventLoop.

If a Promise, MutationObserver, or process.nextTick is called during task execution, it will be saved as a microTask in the microTask Queue.

It’s like doing chores after the fact.

Each time a task is executed, the microTask queue needs to be checked and cleared before the next task is executed.

For example:

setTimeout(() = > console.log('timeout'));
Promise.resolve().then(() = > {
    console.log('promise1');
    Promise.resolve().then(() = > console.log('Promise2'));
});
console.log('global');
Copy the code

The execution process is:

  1. “Globally scoped code execution” is the first task.

  2. SetTimeout is called during execution, and the timer thread handles the timing and adds the timer callback to the Task Queue when the timing ends.

  3. Resolve is called to generate the microTask and insert the microTask queue.

  4. Global printing.

  5. The “globally scoped code execution” task completes, and the microTask Queue is traversed to clean up.

  6. Promise1 printing.

  7. Call Promise.resolve to generate a microTask and insert the current microTask queue.

  8. Continue traversing the microTask Queue and execute microTask to print promise2.

  9. Start the second task, printing timeout.

Execute multiple tasks in one frame

Just as a joss stick can do multiple things in one frame, it can perform multiple tasks in one frame.

After executing the following code, will the screen show red and then black, or will it show black directly?

document.body.style.background = 'red';
setTimeout(function () {
    document.body.style.background = 'black';
})
Copy the code

The answer is: not necessarily.

Global code execution and setTimeout are two different tasks.

If the two tasks are executed in the same frame, the page is rendered once, showing black directly (figure 1 below).

If the two tasks are executed in different frames, the page will be rendered once for each frame, and the screen will show red and then black (figure 2 below).

If we increase the delay time of setTimeout to 17ms, it is almost certain that these two tasks will be executed in different frames, and the probability of “the screen will show red first and then black” will be much higher.

requestAnimationFrame

It can be seen that task cannot accurately control execution timing. So what is the way to ensure that the code executes every frame?

The answer is: use requestAnimationFrame (rAF for short).

RAF will be called before every render frame.

It is usually used to draw animations because render is the next step after the animation code has been executed. Animation effects can be rendered fastest.

What is the result of executing the following code:

setTimeout(() = > {
  console.log("setTimeout1");
  requestAnimationFrame(() = > console.log("rAF1"));
})
setTimeout(() = > {
  console.log("setTimeout2");
  requestAnimationFrame(() = > console.log("rAF2"));
})

Promise.resolve().then(() = > console.log('promise1'));
console.log('global');
Copy the code
Flip to the right to show the answer 👉 most likely:1. global 2. promise1 3. setTimeout1 4. setTimeout2 5. rAF1 6. rAF2                                 
Copy the code

SetTimeout1 and setTimeout2 serve as two tasks and use the default delay time (if no delay time parameter is passed, there will be about 4ms delay), so it is highly likely to be called in the same frame.

RAF1 and rAF2 must be called before render on different frames.

Therefore, most likely we will call setTimeout1, setTimeout2, rAF1 in the same frame, and rAF2 in another frame.

requestIdleCallback

What if I have time left on this frame after RENDER?

In green:

At this point you can use the requestIdleCallbackAPI, which will be called if there is free time after rendering.

Drop frames with time slices

What happens if the task takes too long to execute?

The taskA execution time is over 16.6ms (for example, taskA has a time-consuming while loop).

This frame will have no time to render and the page will not be updated until the next render frame.

This is a page that freezes a frame, or drops a frame. It’s like we don’t have time to map after the grave.

Is there a good solution?

The aforementioned requestIdleCallback is one solution. We can put some of our work into our free time.

However, it still drops frames in the event of a long task.

Better yet: time slices. That is, the long task is divided into several short tasks.

As shown, we split taskA into 2 tasks. Each frame has a chance to render. This reduces the chance of losing frames.

In act15, the virtual DOM tree is built recursively.

If the tree level is deep and the task takes a long time to execute, frame drops may occur.

To get around the frame lag, Act16 changes the recursive build to interruptible traversal.

Tasks are divided by 5ms execution time. After each node is traversed, the current task is checked to see if it has been executed for 5ms.

If the task exceeds 5ms, the task is interrupted.

By dividing the task execution time into smaller segments, it can reduce the render failure of long tasks. This is the time slice.

Touched the touch of gold at hand, I am pleased to think: although 996, but somehow around are living.

In this case, it’s the right turn.