国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

幫你讀懂preact的源碼(一)

XboxYan / 1626人閱讀

摘要:是一個(gè)最小的庫(kù),但由于其對(duì)尺寸的追求,它的很多代碼可讀性比較差,市面上也很少有全面且詳細(xì)介紹的文章,本篇文章希望能幫助你學(xué)習(xí)的源碼。建議與源碼一起閱讀本文。

作為一名前端,我們需要深入學(xué)習(xí)react的運(yùn)行機(jī)制,但是react源碼量已經(jīng)相當(dāng)龐大,從學(xué)習(xí)的角度,性?xún)r(jià)比不高,所以學(xué)習(xí)一個(gè)react mini庫(kù)是一個(gè)深入學(xué)習(xí)react的一個(gè)不錯(cuò)的方法。

preact是一個(gè)最小的react mini庫(kù),但由于其對(duì)尺寸的追求,它的很多代碼可讀性比較差,市面上也很少有全面且詳細(xì)介紹的文章,本篇文章希望能幫助你學(xué)習(xí)preact的源碼。

在最開(kāi)始我會(huì)先介紹preact整體流程,幫助您有一個(gè)整體概念,以便不會(huì)陷入源碼的細(xì)枝末節(jié)里,然后會(huì)分別講解preact各個(gè)值得學(xué)習(xí)的機(jī)制。建議與preact源碼一起閱讀本文。

希望能幫你理清如下問(wèn)題:

JSX是怎么被處理的?

diff算法是如何工作的?

vue和react中我們?yōu)槭裁葱枰粋€(gè)穩(wěn)定的key?

preact是怎么處理事件的?

preact的回收機(jī)制是如何提高性能的?

setState之后會(huì)發(fā)生什么?

fiber是用來(lái)解決什么問(wèn)題的?

以下圖是preact源碼大致流程圖,現(xiàn)在看不懂沒(méi)關(guān)系,也不需要刻意記,在學(xué)習(xí)的過(guò)程中,不妨根據(jù)此圖試著猜想preact每一步都做了什么,下一步要做什么。

JSX

在react的官方文檔中,我們可以得知,jsx內(nèi)容在會(huì)被babel編譯為以下格式:

In

const element = (
  

Hello, world!

); Out const element = React.createElement( "h1", {className: "greeting"}, "Hello, world!" );

這樣通過(guò)createElement就可以生成虛擬dom樹(shù),在preact里面對(duì)應(yīng)的函數(shù)是h。
h函數(shù)根據(jù)nodeName,attributes,children,返回一個(gè)虛擬dom樹(shù),這個(gè)虛擬dom樹(shù)往往有三個(gè)屬性:

function h(nodeName, props, ...children){
    .... // 其他代碼
    return {
        nodeName,
        props,     // props中包含children
        key,       // 為diff算法做準(zhǔn)備
    }
}

這里不貼出preact的源代碼,因?yàn)閔函數(shù)的實(shí)現(xiàn)方式有很多,不希望最開(kāi)始的學(xué)習(xí)就陷入到細(xì)枝末節(jié),只需要明白h函數(shù)的作用即可。

diff

從上圖中可以看到,preact主流程調(diào)用的第一個(gè)函數(shù)就是render,render函數(shù)很簡(jiǎn)單就是調(diào)用了一下diff函數(shù)。

    function render(vnode, parent, merge) {
        return diff(merge, vnode, {}, false, parent, false);
    }

diff函數(shù)的主要作用是調(diào)用idiff函數(shù),然后將idff函數(shù)返回的真實(shí)dom append到dom中

function diff(dom, vnode, context, mountAll, parent, componentRoot) {
    // 返回的是一個(gè)真實(shí)的dom節(jié)點(diǎn)
    let ret = idiff(dom, vnode, context, mountAll, componentRoot);

    // append the element if its a new parent
    if (parent && ret.parentNode !== parent) parent.appendChild(ret);
}
idiff

接下來(lái)我們要介紹idff函數(shù),開(kāi)啟react高性能diff算法的大門(mén),但在這之前,我們應(yīng)該了解react diff算法的前提:

兩個(gè)不同類(lèi)型的element會(huì)產(chǎn)生不同類(lèi)型的樹(shù)。

開(kāi)發(fā)者通過(guò)一個(gè)key標(biāo)識(shí)同一層級(jí)的子節(jié)點(diǎn)。

基于第一個(gè)前提,不同類(lèi)型的節(jié)點(diǎn)就可以不再向下比較,直接銷(xiāo)毀,然后重新創(chuàng)建即可。

idiff函數(shù)主要分為三塊,分別處理vnode三種情況:

vnode是string或者Number,類(lèi)似于上面例子的"Hello World",一般是虛擬dom樹(shù)的葉子節(jié)點(diǎn)。

vnode中的nodeName是一個(gè)function,即vnode對(duì)應(yīng)一個(gè)組件,例如上例中的

vnode中nodeName是一個(gè)字符串,即vnode對(duì)應(yīng)一個(gè)html元素,例如上例中的h1。

對(duì)于string或Number:

// 如果要比較的dom是一個(gè)textNode,直接更改dom的nodeValue
// 如果要比較的dom不是一個(gè)textNode,就創(chuàng)建textNode,然后回收老的節(jié)點(diǎn)樹(shù),回收的節(jié)點(diǎn)樹(shù)會(huì)保留結(jié)構(gòu),然后保存在內(nèi)存中,在// 需要的時(shí)候復(fù)用。(回收相關(guān)的處理會(huì)在之后詳細(xì)說(shuō)明)
if (typeof vnode === "string" || typeof vnode === "number") {

    // update if it"s already a Text node:
    if (dom && dom.splitText !== undefined && dom.parentNode && (!dom._component || componentRoot)) {
        /* istanbul ignore if */
        /* Browser quirk that can"t be covered: https://github.com/developit/preact/commit/fd4f21f5c45dfd75151bd27b4c217d8003aa5eb9 */
        if (dom.nodeValue != vnode) {
            dom.nodeValue = vnode;
        }
    } else {
        // it wasn"t a Text node: replace it with one and recycle the old Element
        out = document.createTextNode(vnode);
        if (dom) {
            if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
            recollectNodeTree(dom, true);
        }
    }

    out.__preactattr_ = true;

    return out;
}

如果nodeName是一個(gè)function,會(huì)直接調(diào)用buildComponentFromVNode方法

let vnodeName = vnode.nodeName;
if (typeof vnodeName === "function") {
    return buildComponentFromVNode(dom, vnode, context, mountAll);
}

如果nodeName是一個(gè)字符串,以下很長(zhǎng)的代碼,就是做三步:

對(duì)于類(lèi)型不同的節(jié)點(diǎn),直接做替換操作,不做diff比較。

diffAttrites

diffChildren

// Tracks entering and exiting SVG namespace when descending through the tree.
isSvgMode = vnodeName === "svg" ? true : vnodeName === "foreignObject" ? false : isSvgMode;

// If there"s no existing element or it"s the wrong type, create a new one:
vnodeName = String(vnodeName);
// 如果不存在dom對(duì)象,或者dom的nodeName和vnodeName不一樣的情況下
if (!dom || !isNamedNode(dom, vnodeName)) {
    out = createNode(vnodeName, isSvgMode);

    if (dom) {
        // 在后面你會(huì)發(fā)現(xiàn)preact的diffChildren的方式,是通過(guò)把真實(shí)dom的子節(jié)點(diǎn)與虛擬dom的子節(jié)點(diǎn)相比較,所以需要老的// 孩子暫時(shí)先移動(dòng)到新的節(jié)點(diǎn)上
        // move children into the replacement node
        while (dom.firstChild) {
            out.appendChild(dom.firstChild);
        } // if the previous Element was mounted into the DOM, replace it inline
        if (dom.parentNode) dom.parentNode.replaceChild(out, dom);

        // recycle the old element (skips non-Element node types)
        recollectNodeTree(dom, true);
    }
}

let fc = out.firstChild,
    props = out.__preactattr_,
    vchildren = vnode.children;
// 把dom節(jié)點(diǎn)的attributes都放在了dom["__preactattr_"]上
if (props == null) {
    props = out.__preactattr_ = {};
    for (let a = out.attributes, i = a.length; i--;) {
        props[a[i].name] = a[i].value;
    }
}

// 如果vchildren只有一個(gè)節(jié)點(diǎn),且是textnode節(jié)點(diǎn)時(shí),直接更改nodeValue,優(yōu)化性能
// Optimization: fast-path for elements containing a single TextNode:
if (!hydrating && vchildren && vchildren.length === 1 && typeof vchildren[0] === "string" && fc != null && fc.splitText !== undefined && fc.nextSibling == null) {
    if (fc.nodeValue != vchildren[0]) {
        fc.nodeValue = vchildren[0];
    }
}

// 比較子節(jié)點(diǎn),將真實(shí)dom的children與vhildren比較
// otherwise, if there are existing or new children, diff them:
else if (vchildren && vchildren.length || fc != null) {
    innerDiffNode(out, vchildren, context, mountAll, hydrating || props.dangerouslySetInnerHTML != null);
}

diffAttributes(out, vnode.attributes, props);

return out;

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/95136.html

相關(guān)文章

  • 幫你讀懂preact源碼(三)

    摘要:對(duì)回收的處理在中,回收調(diào)用了兩個(gè)方法,節(jié)點(diǎn)的回收一般會(huì)調(diào)用,組件的回收會(huì)調(diào)用。個(gè)人理解從以上源碼閱讀中我們可以看到,最大的性能問(wèn)題在于遞歸的,中的與也是為了緩解這個(gè)問(wèn)題。為不同類(lèi)型的更新分配優(yōu)先級(jí)。 對(duì)回收的處理 在preact中,回收調(diào)用了兩個(gè)方法,dom節(jié)點(diǎn)的回收一般會(huì)調(diào)用recollectNodeTree,組件的回收會(huì)調(diào)用unmountComponent。 preact復(fù)用dom...

    yuanxin 評(píng)論0 收藏0
  • 幫你讀懂preact源碼(二)

    摘要:最后刪除新的樹(shù)中不存在的節(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是如何處理...

    Warren 評(píng)論0 收藏0
  • 源碼入手,文帶你讀懂Spring AOP面向切面編程

    摘要:,,面向切面編程。,切點(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都是英文寫(xiě)的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...

    wawor4827 評(píng)論0 收藏0
  • 少啰嗦!分鐘帶你讀懂JavaNIO和經(jīng)典IO區(qū)別

    摘要:的選擇器允許單個(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之...

    Meils 評(píng)論0 收藏0
  • 篇文章教你讀懂UI繪制流程

    摘要:最近有好多人問(wèn)我沒(méi)信心去深造了,找不到好的工作,其實(shí)我以一個(gè)他們進(jìn)行回復(fù),發(fā)現(xiàn)他們主要是內(nèi)心比較浮躁,要知道技術(shù)行業(yè)永遠(yuǎn)缺少的是高手。至此整體繪制過(guò)程我們就已經(jīng)非常清楚了。我門(mén)可以根據(jù)這種繪制的流程來(lái)操作自己的自定義組件。 最近有好多人問(wèn)我Android沒(méi)信心去深造了,找不到好的工作,其實(shí)我以一個(gè)他們進(jìn)行回復(fù),發(fā)現(xiàn)他們主要是內(nèi)心比較浮躁,要知道技術(shù)行業(yè)永遠(yuǎn)缺少的是高手。建議先閱讀淺談A...

    ghnor 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<