Article directory
- Browser rendering mechanism
-
- event loop mechanism
-
- Macro queue and micro queue
- Event loop process in browser
- requestAnimationFrame(rAF)
-
- requestAnimationFrame API
- requestIdleCallback
-
- requestIdleCallback API
- Task splitting
-
- Usage scenarios of requestIdleCallback
Browser rendering mechanism
- Will each round of
Event Loop
be accompanied by rendering? - At which stage is
requestAnimationFrame
executed, before or after rendering? Before or aftermicroTask
?
requestAnimationFrame
is executed before re-rendering the screen - At which stage is
requestIdleCallback
executed? How to implement it? Before or after rendering?
requestIdleCallback
is executed after rendering the screen, and whether it is available for execution depends on the browser’s scheduling.
Event loop mechanism
Function: The function of the event loop mechanism is to coordinate events, user interaction, scripts, rendering and network tasks, etc.
Macro queue and micro queue
An event loop has one or more macro queues and a micro queue
A macro queue is a collection in data structure (called a task queue), and the event loop processing model will obtain a runnable task from the selected task queue. Microqueues are FIFO first-in-first-out queues.
- macro task
- setTimeout, setInterval
- setImmediate(node unique)
- DOM events, Ajax events
- User interaction, user operation events
- script (whole code)
- indexDB operation
- microtasks
- process.nextTick
- Promise some methods, such as .then
- Async/Await (actually promise)
- MutationObserver (html5 new feature)
Event loop process in browser
- Synchronous tasks and asynchronous tasks enter different execution environments. Synchronous tasks are placed in the execution stack, and asynchronous tasks are placed in the task queue.
- Execute synchronous code first
- Check the microtask queue, execute and clear the microtask queue. If a new microtask is added during the execution of the microtask, it will also be executed in this step.
- Enter the update rendering stage to determine whether rendering is required (based on screen refresh rate, page performance, etc.). Not every round of the event loop will perform browser rendering
- If not, start the next cycle and take out a macro task for execution. After a macro task is executed, clear the micro queue and then check whether it is needed. cycle this process
DOM modifications will not cause rendering immediately. The rendering thread and the Javascript thread are mutually exclusive. You must wait for the Javascript schedule to be executed or the thread to hang before rendering can be performed.
This scheduling can be regarded as the completion of an event loop. One event loop = macro task (the first time is synchronization code) + micro task
requestAnimationFrame(rAF)
What
requestAnimationFrame
is a new API in H5 similar to setTimeout
, which tells the browser to execute before re-rendering the screen. The main use is to redraw web pages frame by frame.
rAF is an officially recommended API that should be used to make some smooth animations. When making animations, it is inevitable to change the DOM. If you change the DOM after rendering, you can only wait until the next round of rendering opportunities. Went to draw it
Advantages
Calling time: Called before re-rendering.
The biggest advantage of requestAnimationFrame
is that the system determines the execution timing of the callback function. Ensure that the callback function is only executed once during each screen refresh interval to avoid frame loss
If the browser does not render, will requestAnimationFrame not be called? If requestAnimationFrame does too many things, it will cause frequency reduction, such as refreshing 60 times per second instead of refreshing 30 times per second.
requestAnimationFrame API
Basic syntax: requestAnimationFrame (callback)
Return value: The only value in the callback function list. You can use cancelAnimationFrame
to pass in the request ID to cancel the callback function.
Description
requestAnimationFrame
does not manage callback functions, which means callingrequestAnimationFrame
with the same callback function multiple times will cause the callback to be executed multiple times in the same frame.
The return value of rAF is the only value in the callback function list. It can be understood that even if it is the same callback function, the values in the callback function list are different.
So use it withcancelAnimationFrame
.- When
requestAnimationFrame()
is running in a background tab or a hidden,
requestAnimationFrame()
will be paused to improve performance and Battery Life.
requestIdleCallback
To the human eye, when 60 pictures are switched per second, they are considered coherent. Therefore, the mainstream monitor is 60hz (refreshes 60 times per second), so it needs to be refreshed every 16.7ms. The browser will automatically adapt to this frequency. At this time, the corresponding front-end page needs to be rendered every 16.7ms.
The page is rendered only every 16.7ms, so the time between the two renderings is the browser’s idle time. Tasks performed during this idle time will not block the smoothness of page rendering.
If too many tasks are performed within a certain frame interval, the next frame will never be rendered, and the page will look stuck.
For calculations of a large number of tasks, first consider Web Workers so that they do not occupy the main thread. If you need to operate the DOM, you can consider task splitting.
A frame in the figure includes user interaction, JavaScript script execution; and the call of requestAnimationFrame(rAF)
, layout calculation, page redrawing, etc. If there are not many tasks executed in a certain frame and the above tasks are completed in less than 16.66ms, then this frame will have a certain amount of free time to execute the callback of requestIdleCallback
. Will be called before layout/paint
.
Reflow is also called rearrangement (layout). When changes in the DOM affect the geometric information (position, size, etc.) of the element, the browser needs to recalculate the geometric properties of the element and place it in the correct position on the interface. This process is called reflow. .
When the appearance of an element changes, but the layout is not changed, the process of redrawing the element’s appearance is called repainting.
requestIdleCallback API
Basic syntax: requestIdleCallback(callback,options)
- When
callback
is called, the callback accepts a parameterdeadline
.deadline
is an object with two properties.- The
timeRemaining
attribute is a function. The return value of the function indicates how much time is left in the current idle time. didTimeout
,didTimeout
attribute is a Boolean value. IfdidTimeout
istrue
, then it means thiscallback
is executed due to timeout
- The
options
is an object that can be used to configure the timeout. Iftimeout
is specified, but the browser does not executecallback
within the time specified bytimeout
. At the next idle time,callback
will be forced to execute. And the parameters ofcallback
,deadline.didTimeout=true
,deadline.timeRemaining()
returns 0.
Free time
During idle periods, callbacks are executed in FIFO (first in, first out) order. However, if the callbacks are executed sequentially during the idle time, the execution time of one callback has been used up, and the remaining callbacks will be executed in the next idle time.
const startTask = (deadline) {<!-- --> // If `task` takes 20ms // Exceeding the remaining milliseconds of the current idle time, we wait until the next idle time to execute the task if (deadline.timeRemaining() <= 20) {<!-- --> //Bring the task to the next idle time period //Add to the end of the next idle time period callback list requestIdleCallback(startTask) } else {<!-- --> //Execute task task() } }
When the web page is in an invisible state (such as switching to another tag), the idle time will trigger an idle period every 10 seconds.
Task splitting
Split the batch of tasks to ensure that these tasks are only executed during idle time
. Each time the next task is executed, first check whether the current page should render the next frame, and if so, give up the thread and perform page rendering.
requestIdleCallback
is an API provided by the browser for us to judge this time. It will execute its callback function when the browser is idle. If a timeout is specified, it will be executed in the next frame after the timeout. Enforcement.
const id = window.requestIdleCallback((deadline) => {<!-- --> //The remaining time of the current frame is greater than 0, or the task has timed out if(deadline.timeRemaining() > 0 || deadline.didTimeout) {<!-- --> //do something console.log(1) } }, {<!-- --> timeout: 2000 }) // Specify the timeout period // window.cancelIdleCallback(id) is similar to a timer and supports cancellation
The execution timing of requestIdleCallback
in Event Loop is shown in the figure below. The blue area represents the rendering tasks within one frame. After these tasks are executed, the remaining time is considered idle time.
Use cases
//A method in class idleDownload(){<!-- --> //Cancel the previous one first cancelIdleCallback(this.ridId); // ridId is an attribute in class, which stores the id of a requestIdleCallback const {<!-- --> tasks } = this // tasks is the total number of tasks let index = 0; //Task index const ridOption = {<!-- -->timeout:2000}; // Specify the timeout, which will be enforced in the next frame after the timeout. //Callback function executed when the current frame is idle const handler = (idleDeadline) => {<!-- --> const {<!-- -->timeRemaining} = idleDeadline; // Get idle time while(timeRemaining()>0 & amp; & amp; index<tasks.length ){<!-- --> //Execute tasks during idle time index + + ; } // Determine whether the task download is completed if(index< tasks.length){<!-- --> // No longer idle, but the task has not been completed yet this.ridId = requestIdleCallback(handler, ridOption); // Continue to wait for the next free download }else{<!-- --> // Download has been completed } } this.ridId = requestIdleCallback(handler, ridOption); }
Usage scenarios of requestIdleCallback
Applicable scenarios
- Preloading
- Detect stuttering
IfrequestIdleCallback
cannot be executed for a long time, it means that there is no free time, and it is very likely that a freeze has occurred, so it can be reported. It is more suitable for behavioral lags. For example: click a button and add arequestIdleCallback
callback at the same time. If the callback is not executed within a period of time after the click, there is a high probability that it is caused by the click operation. Got stuck. - Split time-consuming tasks
Not applicable scenarios
- Update DOM operation
requestIdleCallback
Before the callback is executed, style changes and layout calculations have been completed. IfDOM
is modified incallback
, all previous layout calculations will be invalid. And if there are operations related to obtaining layout in the next frame, the browser will need to force reflow, which will greatly affect performance. In addition, since the time to modify the DOM is unpredictable, it is easy to exceed the current frame idle threshold. - The callback (
resolve/reject
) ofpromise
is a higher priority task. If a microtask is generated during a frame, the microtask will be executed. Therefore, it will be executed immediately after the requestIdleCallback callback ends, which may bring the risk of timeout to this frame.
// console // free time 1 //Waited for 1000ms // free time 2 // Promise will be executed immediately after acceptance in idle time 1, even if there is no idle time left. Delays the time to enter the next frame requestIdleCallback(() => {<!-- --> console.log('idle time 1') Promise.resolve().then(() => {<!-- --> sleep(1000) console.log('Waited for 1000ms') }) }) requestIdleCallback(() => {<!-- --> console.log('idle time 2') })
Reference article:
Batch tasks cause the page to freeze? Try requestIdleCallback to split the task
Detailed explanation of requestIdleCallback
Exploration of requestAnimationFrame execution mechanism