What does the following code enter

setTimeout((a)= > {
    console.log(1);
}, 0)
console.log(2);
Copy the code

Answer: Output 2, 1.

directory

  • Single threaded model
  • Task queue
  • setTimeout
  • setTimeoutandsetInterval
  • requestAnimationFrame
  • requestidlecallback

Single threaded model

One of the peculiarities of the JavaScript language is single-threading, which means that you can only do one thing at a time, with the previous task waiting.

Why is JavaScript single threaded?

This is mostly about JavaScript usage. Its primary purpose is to interact with users and manipulate the DOM. If JavaScript is multithreaded, there will be A lot of complications. If JavaScript has two threads, A and B. Thread A adds content to the DOM node, and thread B removes the node, which one should be dominant? So, to avoid complexity, it’s single-threaded.

Although HTML5 puts forward the Web Worker standard. The function of Web Worker is to create a multithreaded environment for JavaScript, allowing the main thread to create Worker threads and assign some tasks to the latter to run. However, the child thread is completely controlled by the main thread and cannot manipulate the DOM. So this doesn’t change the single-threaded nature of JavaScript. Generally, Web workers are used in scenarios where there are many computationally intensive or high-latency tasks in the code that can be assigned to Worker threads.

However, when using worker threads, it is important to note that the purpose of worker threads is to make your application run faster, but if the communication time between worker threads and the main thread is longer than the time you do not use worker threads, the result is not worth the loss.

JavaScript in the browser

The browser kernel is multi-process

  • Brower process (main process)
    • Responsible for browser page display and user interaction. Such as forward, backward
    • Page forward, back
    • Responsible for page management, creating and destroying other processes
  • GPU process
    • 3 d rendering
  • Plug-in process
    • Each type of plug-in corresponds to a process that can only be created when the plug-in is used
  • Browser renderer (browser kernel)
    • GUI rendering thread
      • DOM parsing, CSS parsing, rendering tree generation
    • Js engine thread
      • Executing Js code
    • Events trigger
      • Manages a task queue
    • Asynchronous HTTP request threads
    • Timing trigger thread

You can see that the JS engine is a thread of the browser renderer process.

The relationship between threads in the browser kernel

  • GUI rendering threads and JS engine threads are mutually exclusive
    • Js can manipulate the DOM, and if you render the page while modifying these elements (the JS thread and the UI thread are running at the same time), the element data obtained before and after the render thread may not be consistent.
  • JS blocks page loading
    • Js will block the page if it takes too long to execute

Browsers are an advantage of multiple processes

  • By default, a new TAB page creates a new process, so the crash of a single TAB page does not affect the entire browser.
  • Crashes of third-party plug-ins do not affect the entire browser.
  • Multiple processes can take full advantage of modern cpus with multiple cores.
  • It is convenient to use sandbox model to isolate processes such as plug-ins and improve browser stability.

What about processes and threads

Process and thread are the basic concepts of operating system.

  • A process is the smallest unit of CPU resource allocation (the smallest unit that can own resources and run independently).
  • A thread is the smallest unit of CPU scheduling (the unit of a program run based on a process).

Since each process has to do at least one thing, a process has at least one thread. The system allocates independent memory to each process, so the process has its own resources. Threads within the same process share the memory space of that process (including code segments, data sets, heaps, etc.). Processes can be thought of as separate workshops in a factory. Threads are workshop workers who can do their own thing or work together to do the same thing.

If you want to know more, I recommend WebKit Tech Insider.

Task queue

Single-threaded means that all tasks are queued until the first one is finished before the next one is executed.

If a task needs to be executed, but the JavaScript engine is performing other tasks at the moment, the task needs to be placed in a queue and wait. Until the thread is idle and can be removed from the queue first add tasks to perform (similar to the us to line up bank to handle the business, said single thread is equivalent to the bank is only one service window, can only serve one person at a time, you need to line up behind, and task queue is a queue area, the first priority service)

Note: If the current thread is free and the queue is empty, each function added to the queue will be executed immediately.

Why is there a task queue? Since JS is single threaded, executing tasks synchronously would cause browser blocks, so we split JS into one task after another and execute tasks in the event queue through an endless loop.

setTimeout

The operation mechanism of setTimeout: When executing this statement, the current timer code is immediately pushed into the event queue. When the timer meets the set time value in the event list, the incoming function is added to the task queue, and the task queue is responsible for the subsequent execution. However, if the task queue is not empty at this time, it needs to wait, so the execution time of the code in the timer may be longer than the set time

Now let’s go back to our original example

setTimeout((a)= > {
    console.log(1);
}, 0)
console.log(2);
Copy the code

Output 2, 1;

The second parameter of setTimeout indicates the number of milliseconds to wait before executing the code. In the above code, set to 0, ostensibly meaning that the number of milliseconds to wait before executing the code is 0, i.e., execute immediately. But the actual results we see are not what they appear to be, so don’t be fooled.

In fact, the above code does not execute immediately, because setTimeout has a minimum execution time, and the HTML5 standard states that the second argument to setTimeout() must be at least 4 milliseconds. When the specified time is lower than that, the browser uses the minimum allowed time as the setTimeout interval, meaning that even if we set the setTimeout delay to 0, it could actually be 4 milliseconds before the event is pushed to the task queue.

The timer code is pushed to the event list before it is pushed to the task queue. When the timer meets the specified time value in the event list, it is pushed to the task queue. However, if the task queue is not empty at this time, it needs to wait, so the execution time of the timer code may be longer than the set time

setTimeout((a)= > {
    console.log(111);
}, 100);
Copy the code

The above code indicates that console.log(111) will be executed after 100ms, but the actual execution time must be greater than 100ms. 100ms simply means that the task will be added to the “task queue” after 100ms, and the main thread will not execute its specified callback function until the current code (execution stack) is complete. If the current code takes a long time, it may take a long time, so there is no guarantee that the callback will be executed at setTimeout().

SetTimeout is different from setInterval

  • SetTimeout: The function will be called after the specified delay, and it will be executed after each time setTimeout expires, and then it will continue to execute setTimeout after a period of time. There will be more error in the middle (the error is related to the execution time of the code).
  • SetInterval: calls functions at specified intervals. SetInterval pushes events at precise intervals each time (however, the execution time of the event is not necessarily accurate, and the next event may come before the execution of this event is complete).

The following example references an example from the first article in the in-depth Understanding timer series, understanding setTimeout and setInterval

btn.onclick = function(){
    setTimeout(function(){
        console.log(1);
    },250);
}
Copy the code

After clicking the button, the onclick event handler is first queued. After the program is executed, the timer is set, and after another 250ms, the specified code is added to the queue for execution. If the onclick event handler in the above code executes for 300ms, the timer code will not be executed until at least 300ms after the timer is set. All code in the queue will not be executed until the javascript process is idle, regardless of how it was added to the queue.

As shown, although the timer code is added at 255ms, it cannot be executed at this point because the onclick event handler is still running. The earliest time the timer code can execute is at 300ms, after the onclick event handler has finished.

Some problems with setInterval:

Polling is enabled using setInterval in JavaScript. The timer code may not complete execution until the code is added to the queue again, resulting in the timer code running several times in a row without any pauses in between. The javascript engine’s solution to this problem is that when setInterval() is used, the timer code is added to the queue only if there are no other code instances of the timer. This ensures that the minimum interval between the timer code joining the queue is the specified interval.

However, this leads to two problems:

  • 1. Some intervals are skipped;
  • 2. The interval between code execution of multiple timers may be smaller than expected

Suppose an onclick event handler uses setInterval() to set a timer for a 200ms interval. If the event handler takes a little more than 300ms to complete and the timer code takes a similar amount of time, an interval will be skipped at the same time

The first timer in the example is added to the queue at 205ms, but can’t be executed until after 300ms. When this timer code is executed, another copy is added to the queue at 405ms. At the next interval, 605ms, the first timer code is still running, and there is already an instance of the timer code in the queue. As a result, the timer code at this point in time is not added to the queue

Using setTimeout to construct a poll ensures the interval between each poll.

setTimeout(function () {
 console.log('I'm called.');
 setTimeout(arguments.callee, 100);
}, 100);

Copy the code

Callee is a property of the Arguments object. It can be used for functions that are currently executing in the body of a function that references the function. In strict mode, version 5 of ECMAScript (ES5) prohibits the use of arguments.callee(). Avoid using arguments.callee() when a function must call itself, by either giving the function expression a name or using a function declaration.

setTimeout(function fn(){
    console.log('I'm called.');
    setTimeout(fn, 100);
},100);
Copy the code

This pattern chain calls setTimeout(), creating a new timer each time the function is executed. The second setTimeout() calls the currently executing function and sets another timer for it. The advantage of this is that no new timer code is inserted into the queue until the previous timer code has finished executing, ensuring that there are no missing intervals. Moreover, it ensures that at least a specified interval will be waited before the next timer code executes, avoiding successive runs.

requestAnimationFrame

60fpsAnd equipment refresh rate

The current screen refresh rate on most devices is 60 times per second. If there is an animation or gradient effect in the page, or if the user is scrolling, the browser will render each frame of the animation or page at the same rate as the screen refresh rate on the device.

Caton: Each frame is budgeted for just over 16 milliseconds (1 second / 60 = 16.6 milliseconds). But in reality, the browser has tidy work to do, so all your work needs to be done in 10 milliseconds. If you don’t meet this budget, the frame rate drops and the content shakes on the screen. This phenomenon is commonly referred to as stalling and can negatively impact the user experience.

Frame hopping: if the animation switch is switched at 16ms, 32ms and 48ms respectively, frame hopping means that if the animation cutting frame is executed at 32ms, other tasks have not been completed, and the animation cutting frame has reached the 48ms cutting frame execution. It’s like when you’re playing a game and you get stuck, and after a while, you look at the screen and it doesn’t stop where you’re stuck, or your character has already died. It must be drawn before the next frame begins;

Chrome DevTool to view real-time FPS, open More Tools => Rendering and check FPS Meter

requestAnimationFrameRealization of animation

RequestAnimationFrame is a browser interface for timed loops, similar to setTimeout, that redraw a web page frame by frame.

Before requestAnimationFrame, we mainly use setTimeout/ setInterval to write JS animation. The key of animation is to set the time interval between animation frames. This time interval should be set carefully, on the one hand, it should be small enough. In this way, there is continuity between animation frames and the animation effect is smooth and smooth; On the other hand, be large enough to ensure that the browser has enough time to complete the rendering in a timely manner.

The basic idea of requestAnimationFrame is to synchronize the display with a fixed refresh rate (60Hz or 75Hz), which means it can only be redrawn 60 or 75 times per second at most. In addition, using this API, the page automatically stops refreshing once it is not in the browser’s current TAB. This saves CPU, GPU and power.

RequestAnimationFrame is done on the main thread. This means that if the main thread is very busy, the animation of the requestAnimationFrame will be compromised.

RequestAnimationFrame takes a callback function as an argument. This callback is called before the browser redraws.

requestID = window.requestAnimationFrame(callback); 
Copy the code
window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       || 
            window.webkitRequestAnimationFrame || 
            window.mozRequestAnimationFrame    || 
            window.oRequestAnimationFrame      || 
            window.msRequestAnimationFrame     || 
            function( callback ){
            window.setTimeout(callback, 1000 / 60); }; }) ();Copy the code

The above code simulates the requestAnimationFrame 60 times per second (approximately every 16.7 milliseconds).

requestIdleCallback()

The requestIdleCallback() method queues functions that are called during the browser’s idle time. This enables developers to perform background and low-priority work on the main event loop without affecting the delay of critical events such as animations and input responses. Functions are typically executed in first-come-first-called order; however, if a callback function specifies a timeout, it is possible to scramble the order of execution in order to execute the function before it times out.

RequestAnimationFrame is called each time the screen is refreshed, while requestIdleCallback determines whether the current frame has extra time on each screen refresh, and if so, calls the requestAnimationFrame callback.

The picture shows two consecutive execution frames, roughly understood as the duration of the two frames is about 16.67, and the yellow part is the idle time. Therefore, the callback function in requestIdleCallback will only be called every time the screen refreshes and there is free time.

With this feature, we can use the idle time of each frame to send data during animation execution, or some low-priority operations that do not affect animation performance, or in combination with requestAnimationFrame, we can achieve some page performance optimization.

React’s Fiber architecture is also based on the requestIdleCallback implementation and provides polyfill in unsupported browsers

conclusion

  • Start with the single-threaded model and task queuessetTimeout(fn, 0)Not immediately.
  • JS animation, withrequestAnimationFramethansetIntervalbetter
  • requestIdleCallback()Often used to cut long tasks, using idle time to execute, to avoid the main thread blocking for a long time.

reference

  • Understand setTimeout and setInterval
  • Js setTimeout, requestAnimationFrame, requestIdleCallback differences and applications
  • Use the requestIdleCallback

other

Recently, WE launched a 100-day front-end advanced plan, which is mainly to dig into the principle behind each knowledge point. Welcome to follow the wechat public account “Mucode star”, and we will study together and punch the clock for 100 days.