130. Use the principle of react fiber to optimize the page rendering stuck problem

1. Page freeze analysis

In the browser, the js thread and the rendering thread share the same main thread
. When encountering some complex computing tasks, the JavaScript running time is too long, it will block the tasks on the rendering thread, resulting in frame drop

There are many optimization options:

  • Split computing tasks and even out multiple frames
  • Enable multi-threaded computing through workers
  • Using wasm to accelerate computing

2. Split computing tasks and evenly divide them into multiple frames

How does React do it?

  • When React updates the page, it will calculate the difference on the virtual dom from top to bottom. If the calculation task takes too long, the rendering thread cannot perform the task within 16 ms, and the page will drop frames/stuck.
  • The idea of ​​React Fiber to solve this problem is to split the rendering/updating process (recursive diff) into a series of small tasks. Check a small part of the tree each time, and see if there is time to continue to the next task after finishing. If there is, continue, if not, hang yourself, and continue when the main thread is not busy

Demo

Execute the following code, the browser will be stuck for about 10s: unable to scroll, unable to edit, unable to close the tab

      function repeat(str, count){
    
    
           let result = ''
           for(let i = 0; i < count; i++){
    
    
               result += str
           }
         return result;
      } 
       console.log(repeat('1', 9999999))

According to the design idea of ​​fiber, split the computing tasks to solve the problem of page stuck

    const repeat = (str, count) => {
    
    
        let maxLoopCount = 999999;
        async function runTask(count, cb) {
    
    
            let taskStr = '';
            let taskResult = new Promise((rs) => {
    
    
            	// window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
                window.requestAnimationFrame(() => {
    
    
                    for (let i = 0; i < count && i < maxLoopCount; i++) {
    
    
                        taskStr += str;
                    }
                    // 拆分任务 每次执行的任务不大于maxLoopCount
                    if (count > maxLoopCount) {
    
    
                        runTask(count - maxLoopCount, (restValue) => {
    
    
                            cb && cb(taskStr + restValue);
                            rs(taskStr + restValue);
                        });
                    } else {
    
    
                        cb && cb(taskStr);
                        rs(taskStr);
                    }
                });
            });
            return taskResult;
        }
        return runTask(count);
    };
    repeat('1', 999999999).then((result) => console.log(result));

Summarize

  • If the js thread occupies the main thread for too long, it will affect the rendering task of the page itself
  • By splitting js tasks, it is ensured that the calculation of complex js tasks can be realized without affecting the rendering process

Guess you like

Origin blog.csdn.net/zm06201118/article/details/116784866