current position:Home>React uses concurrent mode. When the rendering phase exceeds the time slice, high priority tasks jump the queue. How will the lanes on the fiber of the previous task be solved

React uses concurrent mode. When the rendering phase exceeds the time slice, high priority tasks jump the queue. How will the lanes on the fiber of the previous task be solved

2022-04-29 16:37:24segmentfault

React Use concurrent Pattern , When needed to generate updates ( Such as setState), perform markUpdateLaneFromFiberToRoot function , perform

sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);

by fiber.lanes assignment , Indicates that the component has been updated , stay render Stage execution beginwork when , Which needs to be taken fiber.lanes Compare with the priority of this task update , Determine whether the priority of the component is enough ,

else if (!includesSomeLane(renderLanes, updateLanes)) { 
  didReceiveUpdate = false;
  ...
}

But then it will start to generate component child nodes ( Class component render Function return jsx Or the return value of the function component ) The front meeting will execute

workInProgress.lanes = NoLanes;

If there is a task to render 100 A component , It takes a long time , When beginwork To the first 50 A component fiber When the time slice runs out and a high priority task is generated, jump in the queue , The previous task was cancelled , But it was done before beginwork Before 50 A component fiber Of lanes It's emptied , If this high priority task is completed , And then re execute 100 A component fiber Rendering of , front 50 individual fiber Of lanes No, I can't find it




Take the answer 1:

Problem analysis

In general ,React Two versions will be saved lanes, Store separately in workInProgress fiber In the tree , and current fiber In the tree

  • current fiber In the tree lanes It stores the corresponding... Of the current unfinished task lanes
  • workInProgress fiber The tree stores the current render After the task in , The remaining tasks correspond to lanes

once render Always corresponds to one workInProgress The construction of trees , Stored in it lanes It was calculated at this time , The reason is also simple , When every round render In progress , Render its corresponding renderLane It's certain , So we know this round render Will end those tasks ( Every task is with a lane The binding of ), Then, remove the corresponding... Of these tasks lanes, The rest lanes Is the above workInProgress fiber Those defined in the tree lanes.

From the above analysis, you should already know the answer to the question , since workInProgress Stored in the tree lanes Next time render To use , That means , At present render We can get rid of these before it's over lanes Without causing any impact , It's a big deal. I'm rebuilding later workInProgress Just do it again when you're in a tree

Practical example

Consider the following pseudo code , This component will be in mount Will call after fetchData Get remote data , After getting the data, call setList Set up list, There is also an input box , When the content of the input box changes, it will call setName Set up name

function App() {
  const [list, setList] = useState([])
  const [name, setName] = useState('')
  useEffect(() => {
    fetchData(..., (list) => {
      setList(list)
    })
  }, [])
  return (
    <div className="App">
      {name}
      <input onChange={v => setName(v.target.value)}/>
      <List data={list}/>
    </div>
  );
}

There is a situation , When the remote data is returned , And the amount of data returned is large, and rendering may be time-consuming , At the moment when List When the component is half rendered , The user enters the value in the input box , here React, Will stop List Instead of rendering the user's input value name( It is also easy to understand the impact of the return value of the interface on the page , Let users wait for dozens more ms Even longer, this is perfectly acceptable , But if you enter a value in the input box , The interface needs to wait for dozens of ms Will change , Instead, users will be more sensitive to this situation , The first impression is that your application is too laggy , Don't follow me ), Next, let's analyze this period of time React Did those things .

  1. Mount after App State of component :

    //current
    states = {list: [], name: ''}
    updateQueue = []
  2. After the interface returns App State of component

    //current
    states = {list: [], name: ''}
    updateQueue = {
      list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
      name: [],
    }
  3. React It's scheduled updateQueue The highest priority update in , Start a round render The process , At this time, because there is only one update in the update list renderLane Namely setList Of the task initiated lane, That is to say 0b0010

    //current
    states = {list: [], name: ''}
    updateQueue = {
      list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
      name: [],
    }
    
    //workInProgress
    states = {list: remoteData, name: ''}
    updateQueue = {
      list: [],
      name: [],
    }
  4. The user enters a value in the input box , Abort the update of step 3 above workInProgress Calculated to half of lanes and states Will be discarded

    //current
    states = {list: [], name: ''}
    updateQueue = {
      list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
      name: [{lane: 0b0001, payload: ' User entered value '}],
    }
  5. Schedule and render the update task generated by the user input event , The task with low priority caused by the interface will be put on hold

    //current
    states = {list: [], name: ''}
    updateQueue = {
     list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
     name: [{lane: 0b0001, payload: ' User entered value '}],
    }
    //workInProgress
    states = {list: [], name: ' User entered value '}
    updateQueue = {
     list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
     name: [],
    }
  6. The task generated by the user is completed ,workInProgress Medium lanes, and states It's going to be current states

    //current
    states = {list: [], name: ' User entered value '}
    updateQueue = {
    list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
    name: [],
    }
  7. Render the remaining tasks , That is, the task generated by the interface

    //current
    states = {list: [], name: ' User entered value '}
    updateQueue = {
    list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
    name: [],
    }
     
    //workInProgress
    states = {list: remoteData, name: ' User entered value '}
    updateQueue = {
    list: [],
    name: [],
    }
  8. Interface... Data rendering is also completed ,workInProgress Medium lanes, and states It's going to be current states

     //current
     states = {list: remoteData, name: ' User entered value '}
     updateQueue = {
     list: [],
     name: [],
    }
    

Source code , If you have a general idea of the source code , Here's the key code , It will make you better understand the above explanation



Other answers 1:

Problem analysis

In general ,React Two versions will be saved lanes, Store separately in workInProgress fiber In the tree , and current fiber In the tree

  • current fiber In the tree lanes It stores the corresponding... Of the current unfinished task lanes
  • workInProgress fiber The tree stores the current render After the task in , The remaining tasks correspond to lanes

once render Always corresponds to one workInProgress The construction of trees , Stored in it lanes It was calculated at this time , The reason is also simple , When every round render In progress , Render its corresponding renderLane It's certain , So we know this round render Will end those tasks ( Every task is with a lane The binding of ), Then, remove the corresponding... Of these tasks lanes, The rest lanes Is the above workInProgress fiber Those defined in the tree lanes.

From the above analysis, you should already know the answer to the question , since workInProgress Stored in the tree lanes Next time render To use , That means , At present render We can get rid of these before it's over lanes Without causing any impact , It's a big deal. I'm rebuilding later workInProgress Just do it again when you're in a tree

Practical example

Consider the following pseudo code , This component will be in mount Will call after fetchData Get remote data , After getting the data, call setList Set up list, There is also an input box , When the content of the input box changes, it will call setName Set up name

function App() {
  const [list, setList] = useState([])
  const [name, setName] = useState('')
  useEffect(() => {
    fetchData(..., (list) => {
      setList(list)
    })
  }, [])
  return (
    <div className="App">
      {name}
      <input onChange={v => setName(v.target.value)}/>
      <List data={list}/>
    </div>
  );
}

There is a situation , When the remote data is returned , And the amount of data returned is large, and rendering may be time-consuming , At the moment when List When the component is half rendered , The user enters the value in the input box , here React, Will stop List Instead of rendering the user's input value name( It is also easy to understand the impact of the return value of the interface on the page , Let users wait for dozens more ms Even longer, this is perfectly acceptable , But if you enter a value in the input box , The interface needs to wait for dozens of ms Will change , Instead, users will be more sensitive to this situation , The first impression is that your application is too laggy , Don't follow me ), Next, let's analyze this period of time React Did those things .

  1. Mount after App State of component :

    //current
    states = {list: [], name: ''}
    updateQueue = []
  2. After the interface returns App State of component

    //current
    states = {list: [], name: ''}
    updateQueue = {
      list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
      name: [],
    }
  3. React It's scheduled updateQueue The highest priority update in , Start a round render The process , At this time, because there is only one update in the update list renderLane Namely setList Of the task initiated lane, That is to say 0b0010

    //current
    states = {list: [], name: ''}
    updateQueue = {
      list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
      name: [],
    }
    
    //workInProgress
    states = {list: remoteData, name: ''}
    updateQueue = {
      list: [],
      name: [],
    }
  4. The user enters a value in the input box , Abort the update of step 3 above workInProgress Calculated to half of lanes and states Will be discarded

    //current
    states = {list: [], name: ''}
    updateQueue = {
      list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
      name: [{lane: 0b0001, payload: ' User entered value '}],
    }
  5. Schedule and render the update task generated by the user input event , The task with low priority caused by the interface will be put on hold

    //current
    states = {list: [], name: ''}
    updateQueue = {
     list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
     name: [{lane: 0b0001, payload: ' User entered value '}],
    }
    //workInProgress
    states = {list: [], name: ' User entered value '}
    updateQueue = {
     list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
     name: [],
    }
  6. The task generated by the user is completed ,workInProgress Medium lanes, and states It's going to be current states

    //current
    states = {list: [], name: ' User entered value '}
    updateQueue = {
    list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
    name: [],
    }
  7. Render the remaining tasks , That is, the task generated by the interface

    //current
    states = {list: [], name: ' User entered value '}
    updateQueue = {
    list: [{lane: 0b0010, payload: remoteData /*  The data returned by the interface  */ }],
    name: [],
    }
     
    //workInProgress
    states = {list: remoteData, name: ' User entered value '}
    updateQueue = {
    list: [],
    name: [],
    }
  8. Interface... Data rendering is also completed ,workInProgress Medium lanes, and states It's going to be current states

     //current
     states = {list: remoteData, name: ' User entered value '}
     updateQueue = {
     list: [],
     name: [],
    }
    

Source code , If you have a general idea of the source code , Here's the key code , It will make you better understand the above explanation

copyright notice
author[segmentfault],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/115/202204251040514197.html

Random recommended