Fiber est le nouvel algorithme de planification de React et une réimplémentation de l'algorithme de base. React Fiber fragmente le processus de mise à jour. Après l'exécution de chaque processus de mise à jour, le contrôle est renvoyé au module de coordination des tâches de React pour voir s'il y a d'autres tâches urgentes à effectuer. S'il y a des tâches urgentes, effectuez simplement les tâches d'urgence.
L'environnement d'exploitation de ce tutoriel : système Windows 7, React version 17.0.1, ordinateur Dell G3.
La fibre a été introduite après la version React16. La planification, la coordination, l'algorithme de comparaison et le rendu à l'ensemble du niveau de l'architecture sont étroitement liés à la fibre.
Lorsque React rend les composants, l'ensemble du processus depuis le début de setState jusqu'à la fin du rendu est synchrone ("tout en une seule fois"). Si les composants à restituer sont relativement volumineux, l'exécution de js occupera le thread principal pendant longtemps, ce qui entraînera une mauvaise réactivité de la page et rendra la réaction moins efficace dans des applications telles que l'animation et les gestes.
Afin de résoudre ce problème, l'équipe React a réécrit l'algorithme de base en React-Reconciliation après deux ans de travail. Et cette nouvelle fonctionnalité a été publiée dans la version v16. Afin de distinguer les réconciliateurs précédents et suivants, le réconciliateur précédent est généralement appelé réconciliateur de pile, et celui réécrit est appelé réconciliateur de fibre, ou Fiber en abrégé.
L'explication officielle est "React Fiber est une réimplémentation de l'algorithme de base."
La fibre peut améliorer la réactivité et les performances des applications React complexes. Fiber est le nouvel algorithme de planification (algorithme de réconciliation) de React
React Fiber fragmente le processus de mise à jour. Après l'exécution de chaque processus de mise à jour, le contrôle est renvoyé au module de React responsable de la coordination des tâches pour voir s'il y a d'autres tâches urgentes. non, continuez la mise à jour. S'il y a des tâches urgentes, effectuez les tâches urgentes.
Lorsque React rend les composants, l'ensemble du processus depuis le début de setState jusqu'à la fin du rendu est synchrone ("tout en une seule fois"). Si les composants à restituer sont relativement volumineux, l'exécution de js occupera le thread principal pendant longtemps, ce qui entraînera une mauvaise réactivité de la page et rendra la réaction moins efficace dans des applications telles que l'animation et les gestes.
Afin de résoudre ce problème, l'équipe React a réécrit l'algorithme de base de React - reconciliation après deux ans de travail. Et cette nouvelle fonctionnalité a été publiée dans la version v16. Afin de distinguer les réconciliateurs précédents et suivants, le réconciliateur précédent est généralement appelé réconciliateur de pile, et celui réécrit est appelé réconciliateur de fibre, ou Fibre en abrégé.
Le flux de travail du réconciliateur de pile est très similaire au processus d'appel de fonction. La réconciliation de composants enfants dans un composant parent peut être comparée à la récursion d'une fonction (c'est pourquoi on l'appelle réconciliateur de pile). Après setState, React lancera immédiatement le processus de réconciliation, en commençant par le nœud parent (Virtual DOM) et en parcourant pour trouver la différence. Une fois toutes les traversées du DOM virtuel terminées, le réconciliateur peut fournir les informations actuellement nécessaires pour modifier le DOM réel et les transmettre au moteur de rendu pour le rendu, puis le contenu mis à jour sera affiché à l'écran. Pour une arborescence vDOM particulièrement volumineuse, le processus de réconciliation sera très long (x00ms). Pendant cette période, le thread principal est occupé par js, donc toute interaction, mise en page et rendu s'arrêtera, donnant à l'utilisateur le sentiment que la page est terminée. bloqué. .
La planification est un processus de réconciliation des fibres, qui détermine principalement ce qui doit être fait et quand. Le processus de ? montre que dans le réconciliateur de pile, la réconciliation se fait "en une seule fois". Pour les fonctions, cela ne pose pas de problème car nous voulons uniquement les résultats d'exécution de la fonction, mais pour l'interface utilisateur, nous devons également prendre en compte les problèmes suivants :
Donc, idéalement, le processus de réconciliation devrait être comme indiqué dans l'image ci-dessous. Vous n'effectuez qu'une petite tâche à la fois, une fois terminée, vous pouvez « respirer » et revenir. le thread principal pour voir s'il y a quelque chose. Si c'est le cas, les tâches plus prioritaires seront traitées en premier. Sinon, l'exécution continuera (planification coopérative).
Voyons d'abord comment fonctionne React sous Stack-Reconciler. Créez (ou mettez à jour) certains éléments du code, React créera (ou mettra à jour) le DOM virtuel en fonction de ces éléments, puis React modifiera le DOM réel en fonction de la différence entre le DOM virtuel avant et après la mise à jour. Notez que sous le réconciliateur de pile, les mises à jour du DOM sont synchrones, c'est-à-dire que pendant le processus de comparaison du DOM virtuel, si une instance est trouvée mise à jour, les opérations DOM seront effectuées immédiatement .
Sous le conciliateur de fibres, l'opération peut être divisée en plusieurs petites parties et peut être interrompue, donc le fonctionnement synchrone du DOM peut entraîner une désynchronisation de l'arbre de fibres avec le DOM réel. Pour chaque nœud, il stocke non seulement les informations de base de l'élément correspondant, mais stocke également certaines informations pour la planification des tâches. Par conséquent, la fibre n'est qu'un objet, représentant la plus petite unité de travail pouvant être divisée pendant la phase de réconciliation, et correspond un à un à l'instance de réaction dans la figure ci-dessus. Gérez les caractéristiques de l'instance elle-même via l'attribut stateNode
. L'unité de travail suivante de l'unité de travail actuelle est représentée par l'enfant et le frère, et return indique la cible à fusionner avec les résultats renvoyés une fois le traitement terminé, pointant généralement vers le nœud parent. La structure entière est une arborescence de listes chaînées. Une fois l'exécution de chaque unité de travail (fibre) terminée, il vérifiera si elle dispose toujours de la tranche de temps du thread principal. Si tel est le cas, passez à la suivante. Sinon, les autres transactions hautement prioritaires seront traitées en premier et exécutées. continuera jusqu'à ce que le fil principal soit libre. stateNode
属性管理Instance自身的特性。通过child和sibling表征当前工作单元的下一个工作单元,return表示处理完成后返回结果所要合并的目标,通常指向父节点。整个结构是一个链表树。每个工作单元(fiber)执行完成后,都会查看是否还继续拥有主线程时间片,如果有继续下一个,如果没有则先处理其他高优先级事务,等主线程空闲下来继续执行。
fiber { stateNode: {}, child: {}, return: {}, sibling: {}, }复制代码
当前页面包含一个列表,通过该列表渲染出一个button和一组Item,Item中包含一个div,其中的内容为数字。通过点击button,可以使列表中的所有数字进行平方。另外有一个按钮,点击可以调节字体大小。
页面渲染完成后,就会初始化生成一个fiber-tree。初始化fiber-tree和初始化Virtual DOM tree没什么区别,这里就不再赘述。
于此同时,react还会维护一个workInProgressTree。workInProgressTree用于计算更新,完成reconciliation过程。
用户点击平方按钮后,利用各个元素平方后的list调用setState,react会把当前的更新送入list组件对应的update queue中。但是react并不会立即执行对比并修改DOM的操作。而是交给scheduler去处理。
scheduler会根据当前主线程的使用情况去处理这次update。为了实现这种特性,使用了requestIdelCallback
API。对于不支持这个API的浏览器,react会加上pollyfill。
总的来讲,通常,客户端线程执行任务时会以帧的形式划分,大部分设备控制在30-60帧是不会影响用户体验;在两个执行帧之间,主线程通常会有一小段空闲时间,requestIdleCallback
setState({}, callback); // stack concilersetState(() => { return {} }, callback); // fiber conciler复制代码
page Une fois le rendu terminé, un arbre à fibres sera initialisé et généré. Il n'y a aucune différence entre l'initialisation de l'arbre fibre et l'initialisation de l'arbre Virtual DOM, je n'entrerai donc pas dans les détails ici.
🎜🎜🎜 Yu Dans le même temps, React maintiendra également un workInProgressTree. workInProgressTree est utilisé pour calculer les mises à jour et terminer le processus de réconciliation. 🎜🎜🎜🎜Utilisateur Après avoir cliqué sur le bouton carré, utilisez la liste au carré de chaque élément pour appeler setState, et React enverra la mise à jour actuelle à la file d'attente de mise à jour correspondant au composant de liste. Mais React n'effectue pas immédiatement la comparaison et la modification du DOM. Au lieu de cela, laissez le soin au planificateur. 🎜🎜🎜🎜planificateur Cette mise à jour sera traitée en fonction de l'utilisation actuelle du thread principal. Pour implémenter cette fonctionnalité, l'APIrequestIdelCallback
est utilisée. Pour les navigateurs qui ne prennent pas en charge cette API, React ajoutera pollyfill. 🎜🎜En général, les threads clients sont généralement divisés en frames lors de l'exécution des tâches. La plupart des appareils contrôlent 30 à 60 frames sans affecter l'expérience utilisateur ; entre deux frames d'exécution, le thread principal est généralement lorsqu'il y a une courte période d'inactivité, requestIdleCallback peut appeler 🎜Idle Callback🎜 pendant cette 🎜Idle Period🎜 pour effectuer certaines tâches🎜🎜🎜🎜低优先级任务由requestIdleCallback
处理;
高优先级任务,如动画相关的由requestAnimationFrame
处理;
requestIdleCallback
可以在多个空闲期调用空闲期回调,执行任务;
requestIdleCallback
方法提供deadline,即任务执行限制时间,以切分任务,避免长时间执行,阻塞UI渲染而导致掉帧;
一旦reconciliation过程得到时间片,就开始进入work loop。work loop机制可以让react在计算状态和等待状态之间进行切换。为了达到这个目的,对于每个loop而言,需要追踪两个东西:下一个工作单元(下一个待处理的fiber);当前还能占用主线程的时间。第一个loop,下一个待处理单元为根节点。
因为根节点上的更新队列为空,所以直接从fiber-tree上将根节点复制到workInProgressTree中去。根节点中包含指向子节点(List)的指针。
根节点没有什么更新操作,根据其child指针,接下来把List节点及其对应的update queue也复制到workinprogress中。List插入后,向其父节点返回,标志根节点的处理完成。
根节点处理完成后,react此时检查时间片是否用完。如果没有用完,根据其保存的下个工作单元的信息开始处理下一个节点List。
接下来进入处理List的work loop,List中包含更新,因此此时react会调用setState时传入的updater funciton获取最新的state值,此时应该是[1,4,9]。通常我们现在在调用setState传入的是一个对象,但在使用fiber conciler时,必须传入一个函数,函数的返回值是要更新的state。react从很早的版本就开始支持这种写法了,不过通常没有人用。在之后的react版本中,可能会废弃直接传入对象的写法。
setState({}, callback); // stack concilersetState(() => { return {} }, callback); // fiber conciler复制代码
在获取到最新的state值后,react会更新List的state和props值,然后调用render,然后得到一组通过更新后的list值生成的elements。react会根据生成elements的类型,来决定fiber是否可重用。对于当前情况来说,新生成的elments类型并没有变(依然是Button和Item),所以react会直接从fiber-tree中复制这些elements对应的fiber到workInProgress 中。并给List打上标签,因为这是一个需要更新的节点。
List节点处理完成,react仍然会检查当前时间片是否够用。如果够用则处理下一个,也就是button。加入这个时候,用户点击了放大字体的按钮。这个放大字体的操作,纯粹由js实现,跟react无关。但是操作并不能立即生效,因为react的时间片还未用完,因此接下来仍然要继续处理button。
button没有任何子节点,所以此时可以返回,并标志button处理完成。如果button有改变,需要打上tag,但是当前情况没有,只需要标记完成即可。
老规矩,处理完一个节点先看时间够不够用。注意这里放大字体的操作已经在等候释放主线程了。
接下来处理第一个item。通过shouldComponentUpdate钩子可以根据传入的props判断其是否需要改变。对于第一个Item而言,更改前后都是1,所以不会改变,shouldComponentUpdate返回false,复制div,处理完成,检查时间,如果还有时间进入第二个Item。
第二个Item shouldComponentUpdate返回true,所以需要打上tag,标志需要更新,复制div,调用render,讲div中的内容从2更新为4,因为div有更新,所以标记div。当前节点处理完成。
Pour la situation ci-dessus, le div est déjà un nœud feuille et n'a aucun nœud frère, et sa valeur a été mise à jour à ce moment, l'effet généré par le changement de ce nœud doit être fusionné dans le nœud parent. À ce stade, React maintiendra une liste qui enregistre tous les éléments produisant des effets.
Après la fusion, revenez à l'élément du nœud parent et la marque du nœud parent est terminée.
L'unité de travail suivante est Item, avant d'entrer Item, vérifiez l'heure. Mais cette fois, le temps était compté. À ce stade, React doit échanger le thread principal et lui dire de lui allouer du temps à l'avenir pour terminer les opérations restantes.
Le fil principal effectuera ensuite l'opération d'agrandissement de la police. Une fois terminé, exécutez l'opération suivante de réaction, qui est presque la même que le processus de traitement de l'élément précédent. Une fois le traitement terminé, l'ensemble de l'arbre de fibres et le travail en cours sont les suivants :
Une fois terminé, le L'élément revient à la liste et fusionne l'effet. La liste des effets est maintenant la suivante :
À ce stade, la liste revient au nœud racine et fusionne l'effet, et tous les nœuds peuvent être marqués comme terminés. À ce stade, React marque workInProgress comme endingCommit. Cela signifie que vous pouvez entrer dans la phase de validation.
À ce moment-là, ce que vous devez faire est de vérifier si le temps est suffisant. S'il n'y a pas de temps, vous attendrez l'heure pour soumettre la modification au DOM. Après être entré dans l'étape 2, reacDOM mettra à jour le DOM en fonction de la liste d'effets calculée à l'étape 1.
Après la mise à jour du DOM, workInProgress est complètement cohérent avec le DOM Afin de maintenir la cohérence de l'arborescence de fibres actuelle et du DOM, React échange les pointeurs actuels et workinProgress.
En fait, React maintient deux arbres (Double-buffering) la plupart du temps. Cela peut réduire le temps d'allocation de mémoire et de nettoyage des déchets lors de la prochaine mise à jour. Une fois la validation terminée, exécutez la fonction composantDidMount.
En décomposant le processus de rapprochement en petites unités de travail, la page peut répondre aux événements du navigateur plus rapidement. Mais un autre problème n'est toujours pas résolu, c'est-à-dire que si le rendu de réaction en cours de traitement prend beaucoup de temps, le rendu de réaction ultérieur sera toujours bloqué. C'est pourquoi le réconciliateur de fibres ajoute une stratégie prioritaire.
【Recommandations associées : Tutoriel vidéo Redis】
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!