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

資訊專欄INFORMATION COLUMN

【譯】React及React Fiber基本的設計理念

lewif / 2841人閱讀

摘要:基礎的理論概念這篇文章是我的一次嘗試,希望能夠形式化的介紹關于本身的一些理念模型。我對于此實際的理念模型是在每次的更新過程中返回下一個階段的狀態。的目標是提升對在動畫,布局以及手勢方面的友好度。我已經邀請了團隊的成員來對本文檔的準確性進行。

前言

本文主要是對收集到的一些官方或者其他平臺的文章進行翻譯,中間可能穿插一些個人的理解,如有錯誤疏漏之處,還望批評指正。筆者并未研究過源碼,只是希望本文成為那些inspire你的東西的一部分,從而在今后一起去探討和研究React Fiber。

注:絕大多數情況下,以下的第一人稱不代表譯者,而是對應文章的作者,請注意區分。

React basic 基礎的理論概念

??這篇文章是我的一次嘗試,希望能夠形式化的介紹關于react本身的一些理念模型。目的在于基于演繹推理的方式,描述那些給我們靈感讓我們進行這樣的設計的源泉。

??當然,這里的一些設想是具有爭議的,實際的設計也許也會有bug或者疏漏。但是,這也是一個好的開始讓我們去形式化地談論這些。同時,如果你有更好的想法,也歡迎pr。以下讓我們沿著這個思路,從簡單到復雜的去思考這一系列問題,不必擔心,這里沒有太多具體的框架細節。

??實際的關于React的實現是充滿務實主義的,漸進式的,算法優化的,新老代碼交替的,各種調試工具以及任何你能想到的讓他變成更加有用的東西。當然,這些東西也像版本迭代一樣,它們的存在是短暫的,如果它們足夠有用,我們就會不斷的更新他們。再次聲明,實際的實現是非常非常復雜的。

轉換

??React最核心的前提是,UI僅僅是數據->數據的映射。相同的輸入意味著相同輸出。非常簡單的純函數。

function NameBox(name) {
  return { fontWeight: "bold", labelContent: name };
}
"Sebastian Markb?ge" ->
{ fontWeight: "bold", labelContent: "Sebastian Markb?ge" };
抽象

??但是,并不是所有的UI都能這樣做,因為,有些UI是非常復雜的。所以,很重要的一點是,UI能夠被抽象成許許多多可復用的小塊,同時不暴露這些小塊的內部實現細節。就像在一個函數中調用另一個函數一樣。

function FancyUserBox(user) {
  return {
    borderStyle: "1px solid blue",
    childContent: [
      "Name: ",
      NameBox(user.firstName + " " + user.lastName)
    ]
  };
}
{ firstName: "Sebastian", lastName: "Markb?ge" } ->
{
  borderStyle: "1px solid blue",
  childContent: [
    "Name: ",
    { fontWeight: "bold", labelContent: "Sebastian Markb?ge" }
  ]
};
組合

??為了實現可復用這一特性,僅僅只是簡單復用葉子節點,每次都為它們創建一個新的容器是遠遠不夠的。同時我們需要在容器(container)這一層面構建抽象,并且組合其它抽象。在我看來,組合就是將兩個甚至多個抽象變成一個新的抽象。

function FancyBox(children) {
  return {
    borderStyle: "1px solid blue",
    children: children
  };
}

function UserBox(user) {
  return FancyBox([
    "Name: ",
    NameBox(user.firstName + " " + user.lastName)
  ]);
}
狀態

??UI并不僅僅是簡單的服務或者說業務中的邏輯狀態。事實上,對于一個特定的投影而言,很多狀態是具體的,但是對于其他投影,可能不是這樣。例如,如果你正在文本框中輸入,這些輸入的字符可以被復制到另外的tab或者移動設備上(當然你不想復制也沒問題,主要是為了和下一句的例子進行區分)。但是,諸如滾動條的位置這樣的數據,你幾乎從來不會想把它在多個投影中復制(因為在這臺設備上比如滾動條位置是200,但是在其他設備上滾動到200的內容通常來說肯定是不同的)。

??我們更趨向于將我們的數據模型變為不可變的。我們在最頂端將所有能更新狀態的函數串起來,把它們當作一個原子(說成事務可能更容易明白)來對待

function FancyNameBox(user, likes, onClick) {
  return FancyBox([
    "Name: ", NameBox(user.firstName + " " + user.lastName),
    "Likes: ", LikeBox(likes),
    LikeButton(onClick)
  ]);
}

// Implementation Details

var likes = 0;
function addOneMoreLike() {
  likes++;
  rerender();
}

// Init

FancyNameBox(
  { firstName: "Sebastian", lastName: "Markb?ge" },
  likes,
  addOneMoreLike
);

注意:這個例子通過副作用去更新狀態。我對于此實際的理念模型是在每次的更新過程中返回下一個階段的狀態。當然,不這樣做看起來要更簡單一點,但是在以后我們最終還是會選擇改變這個例子采用的方式(因為副作用的缺點太多了)。

緩存

??我們知道,對于純函數而言,一次又一次相同的調用是非常浪費時間和空間的。我們可以對這些函數建立緩存的版本,追蹤最近一次調用的輸入和輸出。下一次就可以直接返回結果,不用再次計算。

function memoize(fn) {
  var cachedArg;
  var cachedResult;
  return function(arg) {
    if (cachedArg === arg) {
      return cachedResult;
    }
    cachedArg = arg;
    cachedResult = fn(arg);
    return cachedResult;
  };
}

var MemoizedNameBox = memoize(NameBox);

function NameAndAgeBox(user, currentTime) {
  return FancyBox([
    "Name: ",
    MemoizedNameBox(user.firstName + " " + user.lastName),
    "Age in milliseconds: ",
    currentTime - user.dateOfBirth
  ]);
}
列表/集合

??大多數UI都是通過很多個列表組成,通過列表中的每個元素產生不同的值(比如data.map(item => ))。這樣就產生了一種天然的層次結構。

??為了管理每個列表元素的狀態,我們可以創建一個Map來管理每個特定的列表元素。

function UserList(users, likesPerUser, updateUserLikes) {
  return users.map(user => FancyNameBox(
    user,
    likesPerUser.get(user.id),
    () => updateUserLikes(user.id, likesPerUser.get(user.id) + 1)
  ));
}

var likesPerUser = new Map();
function updateUserLikes(id, likeCount) {
  likesPerUser.set(id, likeCount);
  rerender();
}

UserList(data.users, likesPerUser, updateUserLikes);

注意:現在我們有多個不同的輸入傳遞給FancyNameBox。那會破壞我們上一節提到的緩存策略,因為我們一次只能記憶一個值。(因為上面的memoize函數的形參只有一個)

續延

??不幸的是,在UI中有太多的list相互嵌套,我們不得不用大量的模板代碼去顯式的管理它們。

??我們可以通過延遲執行將一部分的模板代碼移到我們的主要邏輯之外。例如,通過利用currying(可以通過bind實現)(當然我們知道這樣bind并沒有完整的實現currying)。然后我們通過在核心函數之外的地方傳遞狀態,這樣,我們就能擺脫對模板的依賴。

??這并沒有減少模板代碼,但是至少將它們移動到了核心邏輯之外。

function FancyUserList(users) {
  return FancyBox(
    UserList.bind(null, users)
  );
}

const box = FancyUserList(data.users);
const resolvedChildren = box.children(likesPerUser, updateUserLikes);
const resolvedBox = {
  ...box,
  children: resolvedChildren
};

譯注:這里當然可以采用

function FancyUserList(users) {
  return FancyBox(
    UserList(users, likesPerUser, updateUserLikes)
  );
}

??但是這樣擴展起來就很麻煩,想增加,刪除我們都需要去改FancyUserList里的代碼。最重要的是,如果我們想將likesPerUserupdateUserLikes換成其他的集合和函數的話,我們必須再創建一個函數,如:

function FancyUserList2(users) {
  return FancyBox(
    UserList(users, likesPerUser2, updateUserLikes2)
  );
}

當然,你肯定會想到,直接給FancyUserList設置成接收多個參數不就行了。但是這樣依然存在一個問題,那就是每次你需要用到FancyUserList的時候,都需要帶上所有的參數。要解決也是可以的,比如const foo = FancyUserList.bind(null, data.users),后面需要用的話,直接foo(bar1, func1), foo(bar2, func2)就行了。也實現了設計模式中我們常談到的分離程序中變與不變的部分。但是這樣的實現將bind操作交給了調用者,這一點上可以改進,就像示例中提到的那樣。

狀態映射

??我們很早就知道,一旦我們看見相同的部分,我們能夠使用組合去避免一次又一次重復的去實現相同的部分。我們可以將提取出來那部分邏輯移動并傳遞給更低等級或者說更低層級的函數,這些函數就是我們經常復用的那些函數。

function FancyBoxWithState(
  children,
  stateMap,
  updateState
) {
  return FancyBox(
    children.map(child => child.continuation(
      stateMap.get(child.key),
      updateState
    ))
  );
}

function UserList(users) {
  return users.map(user => {
    continuation: FancyNameBox.bind(null, user),
    key: user.id
  });
}

function FancyUserList(users) {
  return FancyBoxWithState.bind(null,
    UserList(users)
  );
}

const continuation = FancyUserList(data.users);
continuation(likesPerUser, updateUserLikes);
緩存映射

??想在緩存列表中緩存多個元素是比較困難的,你必須弄清楚一些在平衡緩存與頻率之間做得很好的緩存算法,然而這些算法是非常復雜的。

??幸運的是,在同一區域的UI通常是比較穩定的,不會變化的。

??在這里我們依然可以采用像剛剛那種緩存state的技巧,通過組合的方式傳遞memoizationCache

function memoize(fn) {
  return function(arg, memoizationCache) {
    if (memoizationCache.arg === arg) {
      return memoizationCache.result;
    }
    const result = fn(arg);
    memoizationCache.arg = arg;
    memoizationCache.result = result;
    return result;
  };
}

function FancyBoxWithState(
  children,
  stateMap,
  updateState,
  memoizationCache
) {
  return FancyBox(
    children.map(child => child.continuation(
      stateMap.get(child.key),
      updateState,
      memoizationCache.get(child.key)
    ))
  );
}

const MemoizedFancyNameBox = memoize(FancyNameBox);
代數哲學

??你會發現,這有點像PITA(一種類似肉夾饃的食物),通過幾個不同層次的抽象,將你需要的東西(值/參數)一點一點的加進去。有時這也提供了一種快捷的方式,能在不借助第三方的條件下在兩個抽象之間傳遞數據。在React里面,我們把這叫做context.

??有時候數據之間的依賴并不像抽象樹那樣整齊一致。例如,在布局算法中,在完整的確定所有字節點的位置之前,你需要知道各個子節點矩形區域的大小。

Now, this example is a bit "out there". I"ll use Algebraic Effects as proposed for ECMAScript. If you"re familiar with functional programming, they"re avoiding the intermediate ceremony imposed by monads.

譯注:FP理解不深,所以上面段就不翻譯了,以免誤導

function ThemeBorderColorRequest() { }

function FancyBox(children) {
  const color = raise new ThemeBorderColorRequest();
  return {
    borderWidth: "1px",
    borderColor: color,
    children: children
  };
}

function BlueTheme(children) {
  return try {
    children();
  } catch effect ThemeBorderColorRequest -> [, continuation] {
    continuation("blue");
  }
}

function App(data) {
  return BlueTheme(
    FancyUserList.bind(null, data.users)
  );
}
React Fiber體系結構

譯注:為了比較形象的闡釋,故這里將React Stack vs Fiber的視頻貼在這,而不是放在閱讀更多里面。由于在youtube上,為了方便查看,這里錄制了一張gif(有點大,18M,下載時請耐心等待)。

簡介

??React Fiber是一個正在進行中的對React核心算法的重寫。它是過去兩年React團隊研究成果的一個頂峰。

??React Fiber的目標是提升對在動畫,布局以及手勢方面的友好度。它最重要的特性叫做"增量式/漸進式"渲染:即,將渲染工作分割為多個小塊進行,并在各個幀之間傳播。

??其它關鍵的特性包括,1.擁有了暫停,中止以及當有更新來臨的時候重新恢復工作的能力。2.不同的能力對于不同類型的更新分配不同的優先級。3.新的并發原語。

關于本文檔

??在Fiber中引入了幾個新的概念,這些概念僅僅只看代碼是很難真的體會的。本文檔最初只是我在React項目組時的收集,收集一些我整理Fiber的實現的時候的筆記。隨著筆記的增多,我意識到這可能對其他人來說也是一個有益的資源。(譯注:本文檔的作者acdlite是Facebook開發組的一名成員,并不屬于React框架的開發組(這里指實際工作中,而不是gh上的team)。React團隊的leader,舊的核心算法及新的核心算法的提出者是sebmarkbage)

??我將嘗試盡可能用簡單的語言來描述,避免一些不必要的術語。在必要時也會給出一些資源的鏈接。

??請注意我并不是React團隊的一員,也不具備足夠的權威。所以這并不是一份官方文檔。我已經邀請了React團隊的成員來對本文檔的準確性進行review。

??Fiber是一項還在進行中的工作,在它完成前都很可能進行重改。所以本文檔也是如此,隨著時間很可能發生變化。歡迎任何的建議。

??我的目標是,在閱讀本文檔后,在Fiber完成的時候,順著它的實現你能更好的理解它。甚至最終回饋React(譯注:意思是fix bug,pr新特性,解決issue等等)。

準備

??在繼續閱讀前,我強烈建議你確保自己對以下內容已經非常熟悉:

??React Components, Elements, and Instances - "組件"通常來說是一個范圍很大的術語。牢固的掌握這些術語是至關重要的。

??Reconciliation - 對React的協調/調度算法的一個高度概括。

??React基礎理論概念 - 對React中的一些概念模型的抽象描述,第一次讀的時候可能不太能體會。沒關系,以后終會明白的。

??React設計原則 - 請注意其中的scheduling這一小節,非常好的解釋了React Fiber。

回顧

??如果你還沒準備好的話,請重新閱讀上面的"準備"一節。在我們探索之前,讓我們來了解幾個概念。

什么是協調(reconciliation)

??reconciliation:是一種算法,React使用它去區分兩棵樹,從而決定到底哪一部分需要改變。

??update:數據的變化會導致渲染,通常這是setState的結果,最終會觸發重新渲染。

??React API的核心理念是思考/決定/調度怎樣去update,就好像它會導致整個app重新渲染一樣。它讓開發者能夠聲明式地去思考,而不用去擔心如何高效的將app從一個狀態過渡到另一個狀態(A到B,B到C,C再到A等等)。

??事實上,每次變化都重新渲染整個app的方式只能工作在非常小的app上。在現實世界真正的app中,這在性能上花費的代價太大了。React已經在這方面做了優化,在保持好性能的前提下創造出app重新渲染之后的樣子。絕大部分的優化都屬于reconciliation這個過程的一部分。

??Reconciliation是一個隱藏在被廣為熟知的稱作"virtual DOM"的背后的算法。概括起來就是:當你渲染一個React應用的時候,就產生了一棵描述這個應用的節點樹,并存儲在內存中。接下來這棵樹會被刷新,然后翻譯到具體的某個環境中。例如,在瀏覽器環境,它被翻譯成一系列的DOM操作。當app有更新的時候(通常是通過setState),一棵新的樹就產生了。這棵新樹會與之前的樹進行diff,然后計算出更新整個app需要哪些操作。

??雖然Fiber是一個對reconciler完全的重寫,但是React文檔中對核心算法的概括描述仍然是適用的。幾個關鍵點為:

不同的組件類型被假定為會產生本質上不同類型的樹。React不會嘗試對它們進行diff,而是完全地替換舊的樹。(譯注:如

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82487.html

相關文章

  • ELSE 技術周刊(2017.12.11期)

    摘要:業界動態發布版本,同時發布了版本以及首個穩定版本的。程序人生如何用人類的方式進行二關于如何在中進行良好的溝通,避免陷入一些潛在的陷阱。技術周刊由小組出品,匯聚一周好文章,周刊原文。 業界動態 Angular 5.1 & More Now Available Angular發布5.1版本,同時發布了Angular CLI 1.6版本以及首個穩定版本的Angular Material。CL...

    tylin 評論0 收藏0
  • 2017-07-12 前端日報

    摘要:前端日報精選借助和緩存及離線開發中和走進之實現分析總是一知半解的中個常見的陷阱發布核心成員發布了免費的學習視頻中文譯的函數式編程是一種反模式掘金譯更好的表單設計每一頁,一件事實例研究掘金打印龍墨并不簡單結合實現簡單的加載動畫 2017-07-12 前端日報 精選 借助Service Worker和cacheStorage緩存及離線開發JavaScript中toString()和valu...

    zhoutk 評論0 收藏0
  • React系列——React Fiber 架構介紹資料匯總(翻+中文資料)

    摘要:它的主體特征是增量渲染能夠將渲染工作分割成塊,并將其分散到多個幀中。實際上,這樣做可能會造成浪費,導致幀丟失并降低用戶體驗。當一個函數被執行時,一個新的堆棧框架被添加到堆棧中。該堆棧框表示由該函數執行的工作。 原文 react-fiber-architecture 介紹 React Fibre是React核心算法正在進行的重新實現。它是React團隊兩年多的研究成果。 React ...

    taohonghui 評論0 收藏0
  • Deep In React之淺談 React Fiber 架構(一)

    摘要:在上面我們已經知道瀏覽器是一幀一幀執行的,在兩個執行幀之間,主線程通常會有一小段空閑時間,可以在這個空閑期調用空閑期回調,執行一些任務。另外由于這些堆棧是可以自己控制的,所以可以加入并發或者錯誤邊界等功能。 文章首發于個人博客 前言 2016 年都已經透露出來的概念,這都 9102 年了,我才開始寫 Fiber 的文章,表示慚愧呀。不過現在好的是關于 Fiber 的資料已經很豐富了,...

    Jiavan 評論0 收藏0

發表評論

0條評論

lewif

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<