久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

React 整體感知

 鹽焗太陽餅qiqi 2021-01-31

當我們由淺入深地認知一樣新事物的時候,,往往需要遵循 Why > What > How 這樣一個認知過程,。它們是相輔相成,、缺一不可的。而了解了具體的 What 和 How 之后,,往往能夠更加具象地回答理論層面的 Why,,因此,在進入 Why 的探索之前,,我們先整體感知一下 What 和 How 兩個過程,。

What

打開一眼便能看到官方給出的回答。

React 是用于構(gòu)建用戶界面的 JavaScript 庫,。

不知道你有沒有想過,,構(gòu)建用戶界面的方式有千百種,為什么 React 會突出,?站長交易同樣,,我們可以從 里得到回應(yīng)。

我們認為,, React 是用 JavaScript 構(gòu)建快速響應(yīng)的大型 Web 應(yīng)用程序的首選方式,。它在 Facebook 和 Instagram 上表現(xiàn)優(yōu)秀。

可見,,關(guān)鍵是實現(xiàn)了 快速響應(yīng) ,,那么制約 快速響應(yīng) 的因素有哪些呢?React 是如何解決的呢,?

How

讓我們帶著上面的兩個問題,,在遵循真實的React代碼架構(gòu)的前提下,并舍棄部分優(yōu)化代碼和非必要的功能,,將其命名為 HuaMu,。

注意:為了和源碼有點區(qū)分,函數(shù)名首字母大寫,,源碼是小寫,。

CreateElement 函數(shù)

在開始之前,我們先簡單的了解一下JSX,,如果你感興趣,,可以關(guān)注下一篇《JSX背后的故事》。

JSX會被工具鏈Babel編譯為React.createElement(),接著React.createElement()返回一個叫作React.Element的JS對象,。

這么說有些抽象,,通過下面demo看下轉(zhuǎn)換前后的代碼:

// JSX 轉(zhuǎn)換前const el = <h1 title="el_title">HuaMu<h1>;

// 轉(zhuǎn)換后的 JS 對象const el = {

  type:"h1",

  props:{

    title:"el_title",

    children:"HuaMu",

  }

}

可見,,元素是具有 type 和 props 屬性的對象,,而 CreateElement 函數(shù)的主要任務(wù)就是創(chuàng)建該對象。

/**

 * @param {string} type    HTML標簽類型

 * @param {object} props   具有JSX屬性中的所有鍵和值

 * @param {string | array} children 元素樹

 */function CreateElement(type, props, ...children) {

  return {

    type,

    props:{

      ...props,

      children,

    }

  }

}

說明:我們將剩余參數(shù)賦予children,,擴展運算符用于構(gòu)造字面量對象props,對象表達式將按照 key-value 的方式展開,,從而保證 props.children 始終是一個數(shù)組,。接下來,我們一起看下 demo:

CreateElement("h1", {title:"el_title"}, 'hello', 'HuaMu')

// 返回的 JS 對象

{

  "type": "h1",

  "props": {

    "title": "el_title"            // key-value

    "children": ["hello", "HuaMu"] // 數(shù)組類型

  }

}

注意:當 ...children 為空或為原始值時,,React 不會創(chuàng)建 props.children,,但為了簡化代碼,,暫不考慮性能,,我們?yōu)樵贾祫?chuàng)建特殊的類型TEXT_EL。

function CreateElement(type, props, ...children) {

  return {

    type,

    props:{

      ...props,

      children: children.map(child => typeof child === "object" ? child : CreateTextElement(child))

    }

  }

}

function CreateTextElement(text) {

  return {

    type: "TEXT_EL",

    props: {

      nodeValue: text,

      children: []

    }

  }

}

Render 函數(shù)

CreateElement 函數(shù)將標簽轉(zhuǎn)化為對象輸出,,接著 React 進行一系列處理,,Render 函數(shù)將處理好的節(jié)點根據(jù)標記進行添加、更新或刪除內(nèi)容,,最后附加到容器中,。下面簡單的實現(xiàn) Render 函數(shù)是如何實現(xiàn)添加內(nèi)容的:

首先創(chuàng)建對應(yīng)的DOM節(jié)點,然后將新節(jié)點附加到容器中,,并遞歸每個孩子節(jié)點做同樣的操作,。

將元素的 props 屬性分配給節(jié)點。

function Render(el,container) {

// 創(chuàng)建節(jié)點

const dom = el.type === 'TEXT_EL'? document.createTextNode("") : document.createElement(el.type);

el.props.children.forEach(child => Render(child, dom))

// 為節(jié)點分配 props 屬性

const isProperty = key => key !== 'children';

const setProperty = name => dom[name] = el.props[name];

Object.keys(el.props).filter(isProperty).forEach(setProperty)

container.appendChild(dom);

}

注意:文本節(jié)點使用textNode而不是innerText,,是為了保證以相同的方式對待所有的元素 ,。

到目前為止,我們已經(jīng)實現(xiàn)了一個簡易的用于構(gòu)建用戶界面的 JavaScript 庫?,F(xiàn)在,,讓 Babel 使用自定義的 HuaMu 代替 React,將 /** @jsx HuaMu.CreateElement */ 添加到代碼中

并發(fā)模式

在繼續(xù)向下探索之前,,我們先思考一下上面的代碼中,,有哪些代碼制約 快速響應(yīng) 了呢?

是的,,在Render函數(shù)中遞歸每個孩子節(jié)點,,即這句代碼el.props.children.forEach(child => Render(child, dom))存在問題。一旦開始渲染,,便不會停止,,直到渲染了整棵元素樹,我們知道,,GUI渲染線程與JS線程是互斥的,,JS腳本執(zhí)行和瀏覽器布局、繪制不能同時執(zhí)行,。如果元素樹很大,,JS腳本執(zhí)行時間過長,可能會阻塞主線程,,導致頁面掉幀,,造成卡頓,,且妨礙瀏覽器執(zhí)行高優(yōu)作業(yè)。

那如何解決呢,?

通過時間切片的方式,,即將任務(wù)分解為多個工作單元,每完成一個工作單元,,判斷是否有高優(yōu)作業(yè),,若有,則讓瀏覽器中斷渲染,。下面通過requestIdleCallback模擬實現(xiàn):

簡單說明一下:

window.requestIdleCallback(cb[, options]) :瀏覽器將在主線程空閑時運行回調(diào),。函數(shù)會接收到一個IdleDeadline的參數(shù),這個參數(shù)可以獲取當前空閑時間(timeRemaining)以及回調(diào)是否在超時前已經(jīng)執(zhí)行的狀態(tài)(didTimeout),。

React 已不再使用requestIdleCallback,,目前使用 但在概念上是相同的。

依據(jù)上面的分析,,代碼結(jié)構(gòu)如下:

// 當瀏覽器準備就緒時,,它將調(diào)用 WorkLoop

requestIdleCallback(WorkLoop)

let nextUnitOfWork = null;

function PerformUnitOfWork(nextUnitOfWork) {

  // TODO

}

function WorkLoop(deadline) {

  // 當前線程的閑置時間是否可以在結(jié)束前執(zhí)行更多的任務(wù)

  let shouldYield = false;

  while(nextUnitOfWork && !shouldYield) {

    nextUnitOfWork = PerformUnitOfWork(nextUnitOfWork) // 賦值下一個工作單元

    shouldYield = deadline.timeRemaining() < 1;  // 如果 idle period 已經(jīng)結(jié)束,則它的值是 0

  }

  requestIdleCallback(WorkLoop)

}

我們在 PerformUnitOfWork 函數(shù)里實現(xiàn)當前工作的執(zhí)行并返回下一個執(zhí)行的工作單元,,可下一個工作單元如何快速查找呢,?讓我們初步了解 Fibers 吧。

Fibers

為了組織工作單元,,即方便查找下一個工作單元,,需引入fiber tree的數(shù)據(jù)結(jié)構(gòu)。即每個元素都有一個fiber,,鏈接到其第一個子節(jié)點,,下一個兄弟姐妹節(jié)點和父節(jié)點,且每個fiber都將成為一個工作單元,。

// 假設(shè)我們要渲染的元素樹如下const el = (

  <div>

    <h1>

      <p />

      <a />

    </h1>

    <h2 />

  </div>

)

function UseState(initial) {

const oldHook =

wipFiber.alternate &&

wipFiber.alternate.hooks &&

wipFiber.alternate.hooks[hookIndex]

const hook = {

state: oldHook ? oldHook.state : initial,

}

wipFiber.hooks.push(hook)

hookIndex++

return [hook.state]

}

UseState還需返回一個可更新狀態(tài)的函數(shù),,因此,需要定義一個接收action的setState函數(shù),。

action添加到隊列中,,再將隊列添加到fiber。

在下一次渲染時,,獲取old hook的action隊列,,并代入new state逐一執(zhí)行,以保證返回的狀態(tài)是已更新的,。

setState函數(shù)中,,執(zhí)行跟Render函數(shù)類似的操作,將currentRoot設(shè)置為下一個工作單元,以便開始新的渲染,。

function UseState(initial) {

...

const hook = {

state: oldHook ? oldHook.state : initial,

queue: [],

}

const actions = oldHook ? oldHook.queue : []

actions.forEach(action => {

hook.state = action(hook.state)

})

const setState = action => {

hook.queue.push(action)

wipRoot = {

dom: currentRoot.dom,

props: currentRoot.props,

alternate: currentRoot,

}

nextUnitOfWork = wipRoot

deletions = []

}

wipFiber.hooks.push(hook)

hookIndex++

return [hook.state, setState]

}

現(xiàn)在,,我們已經(jīng)實現(xiàn)一個包含時間切片、fiber,、Hooks 的簡易 React,。

結(jié)語

到目前為止,我們從 What > How 梳理了大概的 React 知識鏈路,,后面的章節(jié)我們對文中所提及的知識點進行 Why 的探索,,相信會反哺到 What 的理解和 How 的實踐。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多