本篇文章主要的讲述了关于react框架的原理详解,下面还有很多关于react的深入了解,现在就让我们一起来看看这篇文章吧
React 搞了2年多了,对这门框架可谓又爱又恨,它的优势大家都熟知,但是缺点也渐渐暴露,一个大型项目里,配合
Redux
、ReactRouter
等三方框架后,结合复杂的业务代码量会变得非常大(前端代码常常是以前的1.5倍)。如果前期底层设计得不好,时常面临着开发效率低的问题。下面归纳了一些React框架的核心概念,希望对大家有帮助:
React diff 算法
React的diff
算法是Virtual DOM
之所以任性的最大依仗,大家知道页面的性能 一般是由渲染速度和渲染次数决定,如何最大程度地利用diff
算法进行开发?我们先看看它的原理。
传统 diff 算法
计算一棵树形结构转换成另一棵树形结构的最少操作,传统 diff 算法通过循环递归对节点进行依次对比,效率低下,算法复杂度达到 O(n^3)
,其中 n 是树中节点的总数。也就是说如果要展示1000个节点,就要依次执行上十亿次的比较。这个性能消耗对对于前端项目来说是不可接受的。
核心算法
如上所见,传统 diff 算法的复杂度为 O(n^3)
,显然这是无法满足性能要求的。而React
通过制定大胆的策略,将 O(n^3)
复杂度的问题转换成 O(n)
复杂度的问题。他是怎么做到的?
tree diff
Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计。React 对树的算法进行了简洁明了的优化,即对树进行分层比较,两棵树只会对同一层次的节点进行比较。如下图所示:
React 通过 updateDepth 对 Virtual DOM 树进行层级控制,只会对相同颜色方框内的 DOM 节点进行比较,即同一个父节点下的所有子节点。当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。这样只需要对树进行一次遍历,便能完成整个 DOM 树的比较。
// tree diff算法实现updateChildren: function(nextNestedChildrenElements, transaction, context) { updateDepth++; var errorThrown = true; try { this._updateChildren(nextNestedChildrenElements, transaction, context); errorThrown = false; } finally { updateDepth--; if (!updateDepth) { if (errorThrown) { clearQueue(); } else { processQueue(); } } } }
为什么要减少DOM节点的跨层级操作?
如下图,A 节点(包括其子节点)整个被移动到 D 节点下,由于 React 只会简单的考虑同层级节点的位置变换,而对于不同层级的节点,只有创建和删除操作。当根节点发现子节点中 A 消失了,就会直接销毁 A;当 D 发现多了一个子节点 A,则会创建新的 A(包括子节点)作为其子节点。此时,React diff
的执行情况:create A -> create B -> create C -> delete A。
由此可发现,当出现节点跨层级移动时,并不会出现想象中的移动操作,而是以 A 为根节点的树被整个重新创建,这是一种影响 React
性能的操作。
component diff
拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。
如果是同一类型的组件,按照原策略继续比较
virtual DOM tree
。如果不是,则将该组件判断为
dirty component
,从而替换整个组件下的所有子节点。对于同一类型的组件,有可能其
Virtual DOM
没有任何变化,如果能够确切的知道这点那可以节省大量的 diff 运算时间,因此React
允许用户通过shouldComponentUpdate()
来判断该组件是否需要进行 diff。
如上图,当 component D
改变为 component G
时,即使这两个 component
结构相似,一旦 React
判断 D 和 G 是不同类型的组件,就不会比较二者的结构,而是直接删除 component D
,重新创建 component G
以及其子节点。虽然当两个 component
是不同类型但结构相似时,React diff
会影响性能,但正如 React
官方博客所言:不同类型的 component
是很少存在相似 DOM tree
的机会,因此这种极端因素很难在实现开发过程中造成重大影响的。
element diff
对于同一层级的一组子节点,它们可以通过唯一 id 进行区分。React 提出优化策略:允许开发者对同一层级的同组子节点,添加唯一 key 进行区分,虽然只是小小的改动,性能上却发生了翻天覆地的变化!
新老集合所包含的节点,如下图所示,新老集合进行 diff 差异化对比,通过 key 发现新老集合中的节点都是相同的节点,因此无需进行节点删除和创建,只需要将老集合中节点的位置进行移动,更新为新集合中节点的位置,此时 React 给出的 diff 结果为:B、D 不做任何操作,A、C 进行移动操作,即可。
开发建议
(1)[基于tree diff] 开发组件时,保持稳定的DOM结构有助于维持整体的性能。换而言之,尽可能少地动态操作DOM结构,尤其是移动操作。当节点数过大或者页面更新次数过多时,页面卡顿的现象比较明显。可以通过 CSS 隐藏或显示节点,而不是真的移除或添加 DOM 节点。
(2)[基于component diff] 开发组件时,注意使用 shouldComponentUpdate()
来减少组件不必要的更新。除此之外,对于类似的结构应该尽量封装成组件,既减少代码量,又能减少component diff
的性能消耗。
(3)[基于element diff] 对于列表结构,尽量减少类似将最后一个节点移动到列表首部的操作,当节点数量过大或更新操作过于频繁时,在一定程度上会影响 React 的渲染性能。
React Lifecycle
React的生命周期具体可分为四种情况:
当首次装载组件时,按顺序执行
getDefaultProps
、getInitialState
、componentWillMount
、render
和componentDidMount
;当卸载组件时,执行
componentWillUnmount
;当重新装载组件时,此时按顺序执行
getInitialState
、componentWillMount
、render
和componentDidMount
,但并不执行getDefaultProps
;当再次渲染组件时,组件接受到更新状态,此时按顺序执行
componentWillReceiveProps
、shouldComponentUpdate
、componentWillUpdate
、render
和componentDidUpdate
。
React组件的3种状态
状态一:MOUNTING
mountComponent
负责管理生命周期中的 getInitialState
、componentWillMount
、render
和 componentDidMount
。
状态二:RECEIVE_PROPS
updateComponent
负责管理生命周期中的 componentWillReceiveProps
、shouldComponentUpdate
、componentWillUpdate
、render
和 componentDidUpdate
。
状态三:UNMOUNTING
unmountComponent
负责管理生命周期中的 componentWillUnmount
。(想看更多就到PHP中文网React参考手册栏目中学习)
首先将状态设置为 UNMOUNTING
,若存在 componentWillUnmount
,则执行;如果此时在 componentWillUnmount
中调用 setState
,是不会触发 reRender
。更新状态为 NULL
,完成组件卸载操作。实现代码如下:
// 卸载组件unmountComponent: function() { // 设置状态为 UNMOUNTING this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; // 如果存在 componentWillUnmount,则触发 if (this.componentWillUnmount) { this.componentWillUnmount(); } // 更新状态为 null this._compositeLifeCycleState = null; this._renderedComponent.unmountComponent(); this._renderedComponent = null; ReactComponent.Mixin.unmountComponent.call(this); }
React生命周期总结
生命周期 | 调用次数 | 能否使用setState() |
---|---|---|
getDefaultProps | 1 | 否 |
getInitialState | 1 | 否 |
componentWillMount | 1 | 是 |
render | >=1 | 否 |
componentDidMount | 1 | 是 |
componentWillReceiveProps | >=0 | 是 |
shouldComponentUpdate | >=0 | 否 |
componentWillUpdate | >=0 | 否 |
componentDidUpdate | >=0 | 否 |
componentWillUnmount | 1 | 否 |
componentDidUnmount | 1 | 否 |
setState实现机制
setState
是React
框架的核心方法之一,下面介绍一下它的原理:
// 更新 statesetState: function(partialState, callback) { // 合并 _pendingState this.replaceState( assign({}, this._pendingState || this.state, partialState), callback ); },
当调用 setState
时,会对 state
以及 _pendingState
更新队列进行合并操作,但其实真正更新 state
的幕后黑手是replaceState
。
// 更新 statereplaceState: function(completeState, callback) { validateLifeCycleOnReplaceState(this); // 更新队列 this._pendingState = completeState; // 判断状态是否为 MOUNTING,如果不是,即可执行更新 if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) { ReactUpdates.enqueueUpdate(this, callback); } },
replaceState
会先判断当前状态是否为 MOUNTING
,如果不是即会调用 ReactUpdates.enqueueUpdate
执行更新。
当状态不为 MOUNTING
或 RECEIVING_PROPS
时,performUpdateIfNecessary
会获取 _pendingElement
、_pendingState
、_pendingForceUpdate
,并调用 updateComponent
进行组件更新。
// 如果存在 _pendingElement、_pendingState、_pendingForceUpdate,则更新组件performUpdateIfNecessary: function(transaction) { var compositeLifeCycleState = this._compositeLifeCycleState; // 当状态为 MOUNTING 或 RECEIVING_PROPS时,则不更新 if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING || compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) { return; } var prevElement = this._currentElement; var nextElement = prevElement; if (this._pendingElement != null) { nextElement = this._pendingElement; this._pendingElement = null; } // 调用 updateComponent this.updateComponent( transaction, prevElement, nextElement ); }
如果在
shouldComponentUpdate
或componentWillUpdate
中调用setState
,此时的状态已经从RECEIVING_PROPS -> NULL
,则performUpdateIfNecessary
就会调用updateComponent
进行组件更新,但updateComponent
又会调用shouldComponentUpdate
和componentWillUpdate
,因此造成循环调用,使得浏览器内存占满后崩溃。
开发建议
不建议在 getDefaultProps
、getInitialState
、shouldComponentUpdate
、componentWillUpdate
、render
和 componentWillUnmount
中调用 setState,特别注意:不能在 shouldComponentUpdate
和 componentWillUpdate
中调用 setState
,会导致循环调用。
本篇文章到这就结束了(想看更多就到PHP中文网React使用手册栏目中学习),有问题的可以在下方留言提问。
Atas ialah kandungan terperinci React框架有哪些算法?react框架的算法详解. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

JavaScript berjalan dalam penyemak imbas dan persekitaran Node.js dan bergantung pada enjin JavaScript untuk menghuraikan dan melaksanakan kod. 1) menjana pokok sintaks abstrak (AST) di peringkat parsing; 2) menukar AST ke bytecode atau kod mesin dalam peringkat penyusunan; 3) Laksanakan kod yang disusun dalam peringkat pelaksanaan.

Trend masa depan Python dan JavaScript termasuk: 1. Kedua -duanya akan terus mengembangkan senario aplikasi dalam bidang masing -masing dan membuat lebih banyak penemuan dalam prestasi.

Kedua -dua pilihan Python dan JavaScript dalam persekitaran pembangunan adalah penting. 1) Persekitaran pembangunan Python termasuk Pycharm, Jupyternotebook dan Anaconda, yang sesuai untuk sains data dan prototaip cepat. 2) Persekitaran pembangunan JavaScript termasuk node.js, vscode dan webpack, yang sesuai untuk pembangunan front-end dan back-end. Memilih alat yang betul mengikut keperluan projek dapat meningkatkan kecekapan pembangunan dan kadar kejayaan projek.

Ya, teras enjin JavaScript ditulis dalam C. 1) Bahasa C menyediakan prestasi yang efisien dan kawalan asas, yang sesuai untuk pembangunan enjin JavaScript. 2) Mengambil enjin V8 sebagai contoh, terasnya ditulis dalam C, menggabungkan kecekapan dan ciri-ciri berorientasikan objek C. 3) Prinsip kerja enjin JavaScript termasuk parsing, penyusun dan pelaksanaan, dan bahasa C memainkan peranan penting dalam proses ini.

JavaScript adalah di tengah -tengah laman web moden kerana ia meningkatkan interaktiviti dan dinamik laman web. 1) Ia membolehkan untuk menukar kandungan tanpa menyegarkan halaman, 2) memanipulasi laman web melalui Domapi, 3) menyokong kesan interaktif kompleks seperti animasi dan drag-and-drop, 4) mengoptimumkan prestasi dan amalan terbaik untuk meningkatkan pengalaman pengguna.

C dan JavaScript mencapai interoperabilitas melalui webassembly. 1) Kod C disusun ke dalam modul WebAssembly dan diperkenalkan ke dalam persekitaran JavaScript untuk meningkatkan kuasa pengkomputeran. 2) Dalam pembangunan permainan, C mengendalikan enjin fizik dan rendering grafik, dan JavaScript bertanggungjawab untuk logik permainan dan antara muka pengguna.

JavaScript digunakan secara meluas di laman web, aplikasi mudah alih, aplikasi desktop dan pengaturcaraan sisi pelayan. 1) Dalam pembangunan laman web, JavaScript mengendalikan DOM bersama -sama dengan HTML dan CSS untuk mencapai kesan dinamik dan menyokong rangka kerja seperti JQuery dan React. 2) Melalui reaktnatif dan ionik, JavaScript digunakan untuk membangunkan aplikasi mudah alih rentas platform. 3) Rangka kerja elektron membolehkan JavaScript membina aplikasi desktop. 4) Node.js membolehkan JavaScript berjalan di sisi pelayan dan menyokong permintaan serentak yang tinggi.

Python lebih sesuai untuk sains data dan automasi, manakala JavaScript lebih sesuai untuk pembangunan front-end dan penuh. 1. Python berfungsi dengan baik dalam sains data dan pembelajaran mesin, menggunakan perpustakaan seperti numpy dan panda untuk pemprosesan data dan pemodelan. 2. Python adalah ringkas dan cekap dalam automasi dan skrip. 3. JavaScript sangat diperlukan dalam pembangunan front-end dan digunakan untuk membina laman web dinamik dan aplikasi satu halaman. 4. JavaScript memainkan peranan dalam pembangunan back-end melalui Node.js dan menyokong pembangunan stack penuh.


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

EditPlus versi Cina retak
Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

SublimeText3 versi Inggeris
Disyorkan: Versi Win, menyokong gesaan kod!

Dreamweaver Mac版
Alat pembangunan web visual

Versi Mac WebStorm
Alat pembangunan JavaScript yang berguna

SecLists
SecLists ialah rakan penguji keselamatan muktamad. Ia ialah koleksi pelbagai jenis senarai yang kerap digunakan semasa penilaian keselamatan, semuanya di satu tempat. SecLists membantu menjadikan ujian keselamatan lebih cekap dan produktif dengan menyediakan semua senarai yang mungkin diperlukan oleh penguji keselamatan dengan mudah. Jenis senarai termasuk nama pengguna, kata laluan, URL, muatan kabur, corak data sensitif, cangkerang web dan banyak lagi. Penguji hanya boleh menarik repositori ini ke mesin ujian baharu dan dia akan mempunyai akses kepada setiap jenis senarai yang dia perlukan.
