摘要:對(duì)回收的處理在中,回收調(diào)用了兩個(gè)方法,節(jié)點(diǎn)的回收一般會(huì)調(diào)用,組件的回收會(huì)調(diào)用。個(gè)人理解從以上源碼閱讀中我們可以看到,最大的性能問(wèn)題在于遞歸的,中的與也是為了緩解這個(gè)問(wèn)題。為不同類型的更新分配優(yōu)先級(jí)。
對(duì)回收的處理
在preact中,回收調(diào)用了兩個(gè)方法,dom節(jié)點(diǎn)的回收一般會(huì)調(diào)用recollectNodeTree,組件的回收會(huì)調(diào)用unmountComponent。
preact復(fù)用dom的秘密在于當(dāng)要卸載一個(gè)組件的時(shí)候,只有組件的根節(jié)點(diǎn)會(huì)從父節(jié)點(diǎn)上卸載掉,組件完整的dom仍然存在,被卸載的組件會(huì)保存在components對(duì)象中。
在創(chuàng)建組件的時(shí)候又通過(guò)nodeName拿到對(duì)應(yīng)的dom節(jié)點(diǎn)樹,掛載在組件實(shí)例的inst.nextBase上,在renderComponent的時(shí)候,再diff nextBase與新的虛擬dom樹rendered。
相關(guān)主要代碼如下:
function createComponent(Ctor, props, context) { let list = components[Ctor.name], inst; if (Ctor.prototype && Ctor.prototype.render) { inst = new Ctor(props, context); Component.call(inst, props, context); } else { // 對(duì)應(yīng)函數(shù)組件 inst = new Component(props, context); inst.constructor = Ctor; inst.render = doRender; } if (list) { for (let i = list.length; i--;) { if (list[i].constructor === Ctor) { inst.nextBase = list[i].nextBase; list.splice(i, 1); break; } } } return inst; }setState的處理
更改組件上的state,然后將要渲染的組件放在一個(gè)數(shù)組中,在下一次event loop的時(shí)候渲染:
setState: function setState(state, callback) { let s = this.state; if (!this.prevState) this.prevState = extend({}, s); extend(s, typeof state === "function" ? state(s, this.props) : state); if (callback)(this._renderCallbacks = this._renderCallbacks || []).push(callback); enqueueRender(this); }, function enqueueRender(component) { // component._dirty為false且items原本為空數(shù)組就能渲染 if (!component._dirty && (component._dirty = true) && items.push(component) == 1) { (options.debounceRendering || defer)(rerender); //異步的執(zhí)行render,要執(zhí)行render方法的component中的_dirty設(shè)為true } }, function rerender() { let p, list = items; items = []; while (p = list.pop()) { if (p._dirty) renderComponent(p); } }preact對(duì)事件的處理
preact為了減少增減事件對(duì)性能和內(nèi)存的影響,當(dāng)為dom做事件監(jiān)聽時(shí),添加的是一個(gè)代理函數(shù)。
function setAccessor(node, name, old, value, isSvg) { // ... if (name[0] == "o" && name[1] == "n") { let useCapture = name !== (name = name.replace(/Capture$/, "")); name = name.toLowerCase().substring(2); if (value) { if (!old) node.addEventListener(name, eventProxy, useCapture); } else { node.removeEventListener(name, eventProxy, useCapture); } (node._listeners || (node._listeners = {}))[name] = value; } // ... }
function eventProxy(e) { return this._listeners[e.type](options.event && options.event(e) || e); }fiber(個(gè)人理解)
從以上源碼閱讀中我們可以看到,react最大的性能問(wèn)題在于遞歸的diff,react中的shouldCompnentUpdate與PureComponent也是為了緩解這個(gè)問(wèn)題。但是當(dāng)應(yīng)用比較大的時(shí)候一個(gè)高級(jí)別組件的diff還是很容易使得動(dòng)畫掉幀。
fiber的出現(xiàn)就是為了解決這個(gè)問(wèn)題,react fiber將計(jì)算工作分成了多個(gè)小片,這使得整個(gè)計(jì)算工作可以暫停,中止,或重新開始。為不同類型的更新分配優(yōu)先級(jí)。當(dāng)動(dòng)畫或用戶交互觸發(fā)時(shí),就可以先暫停低優(yōu)先級(jí)的更新工作,保證動(dòng)畫的流暢性,等所有的渲染計(jì)算工作完成,對(duì)dom更新進(jìn)行一次commit。
參考https://calendar.perfplanet.c...
https://reactjs.org/docs/impl...
https://segmentfault.com/a/11...
https://www.w3ctech.com/topic...
https://zhuanlan.zhihu.com/p/...
https://github.com/acdlite/re...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95133.html
摘要:是一個(gè)最小的庫(kù),但由于其對(duì)尺寸的追求,它的很多代碼可讀性比較差,市面上也很少有全面且詳細(xì)介紹的文章,本篇文章希望能幫助你學(xué)習(xí)的源碼。建議與源碼一起閱讀本文。 作為一名前端,我們需要深入學(xué)習(xí)react的運(yùn)行機(jī)制,但是react源碼量已經(jīng)相當(dāng)龐大,從學(xué)習(xí)的角度,性價(jià)比不高,所以學(xué)習(xí)一個(gè)react mini庫(kù)是一個(gè)深入學(xué)習(xí)react的一個(gè)不錯(cuò)的方法。 preact是一個(gè)最小的react mi...
摘要:最后刪除新的樹中不存在的節(jié)點(diǎn)。而中會(huì)記錄對(duì)其做了相應(yīng)的優(yōu)化,節(jié)點(diǎn)的的情況下,不做移動(dòng)操作。這種情況,在中得到了優(yōu)化,通過(guò)四個(gè)指針,在每次循環(huán)中先處理特殊情況,并通過(guò)縮小指針?lè)秶?,獲得性能上的提升。 上篇文章已經(jīng)介紹過(guò)idff的處理邏輯主要分為三塊,處理textNode,element及component,但具體怎么處理component還沒(méi)有詳細(xì)介紹,接下來(lái)講一下preact是如何處理...
摘要:基本介紹選擇式排序也屬于內(nèi)部排序法,是從欲排序的數(shù)據(jù)中,按指定的規(guī)則選出某一元素,再依規(guī)定交換位置后達(dá)到排序的目的。而移動(dòng)次數(shù)與序列的初始排序有關(guān)??臻g復(fù)雜度簡(jiǎn)單選擇排序需要占用個(gè)臨時(shí)空間,在交換數(shù)值時(shí)使用。 showImg(https://img-blog.csdnimg.cn/20190509221741422.gif); showImg(https://segmentfault....
摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過(guò)程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...
摘要:的選擇器允許單個(gè)線程監(jiān)視多個(gè)輸入通道。一旦執(zhí)行的線程已經(jīng)超過(guò)讀取代碼中的某個(gè)數(shù)據(jù)片段,該線程就不會(huì)在數(shù)據(jù)中向后移動(dòng)通常不會(huì)。 1、引言 很多初涉網(wǎng)絡(luò)編程的程序員,在研究Java NIO(即異步IO)和經(jīng)典IO(也就是常說(shuō)的阻塞式IO)的API時(shí),很快就會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題:我什么時(shí)候應(yīng)該使用經(jīng)典IO,什么時(shí)候應(yīng)該使用NIO? 在本文中,將嘗試用簡(jiǎn)明扼要的文字,闡明Java NIO和經(jīng)典IO之...
閱讀 2467·2021-11-08 13:13
閱讀 1402·2021-10-09 09:41
閱讀 1878·2021-09-02 15:40
閱讀 3348·2021-08-17 10:13
閱讀 2683·2019-08-29 16:33
閱讀 3281·2019-08-29 13:17
閱讀 3270·2019-08-29 11:00
閱讀 3433·2019-08-26 13:40