成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

【譯】React及React Fiber基本的設(shè)計(jì)理念

lewif / 2906人閱讀

摘要:基礎(chǔ)的理論概念這篇文章是我的一次嘗試,希望能夠形式化的介紹關(guān)于本身的一些理念模型。我對于此實(shí)際的理念模型是在每次的更新過程中返回下一個(gè)階段的狀態(tài)。的目標(biāo)是提升對在動(dòng)畫,布局以及手勢方面的友好度。我已經(jīng)邀請了團(tuán)隊(duì)的成員來對本文檔的準(zhǔn)確性進(jìn)行。

前言

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

注:絕大多數(shù)情況下,以下的第一人稱不代表譯者,而是對應(yīng)文章的作者,請注意區(qū)分。

React basic 基礎(chǔ)的理論概念

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

??當(dāng)然,這里的一些設(shè)想是具有爭議的,實(shí)際的設(shè)計(jì)也許也會(huì)有bug或者疏漏。但是,這也是一個(gè)好的開始讓我們?nèi)バ问交卣務(wù)撨@些。同時(shí),如果你有更好的想法,也歡迎pr。以下讓我們沿著這個(gè)思路,從簡單到復(fù)雜的去思考這一系列問題,不必?fù)?dān)心,這里沒有太多具體的框架細(xì)節(jié)。

??實(shí)際的關(guān)于React的實(shí)現(xiàn)是充滿務(wù)實(shí)主義的,漸進(jìn)式的,算法優(yōu)化的,新老代碼交替的,各種調(diào)試工具以及任何你能想到的讓他變成更加有用的東西。當(dāng)然,這些東西也像版本迭代一樣,它們的存在是短暫的,如果它們足夠有用,我們就會(huì)不斷的更新他們。再次聲明,實(shí)際的實(shí)現(xiàn)是非常非常復(fù)雜的。

轉(zhuǎn)換

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

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

??但是,并不是所有的UI都能這樣做,因?yàn)?,有些UI是非常復(fù)雜的。所以,很重要的一點(diǎn)是,UI能夠被抽象成許許多多可復(fù)用的小塊,同時(shí)不暴露這些小塊的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。就像在一個(gè)函數(shù)中調(diào)用另一個(gè)函數(shù)一樣。

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" }
  ]
};
組合

??為了實(shí)現(xiàn)可復(fù)用這一特性,僅僅只是簡單復(fù)用葉子節(jié)點(diǎn),每次都為它們創(chuàng)建一個(gè)新的容器是遠(yuǎn)遠(yuǎn)不夠的。同時(shí)我們需要在容器(container)這一層面構(gòu)建抽象,并且組合其它抽象。在我看來,組合就是將兩個(gè)甚至多個(gè)抽象變成一個(gè)新的抽象。

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

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

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

??我們更趨向于將我們的數(shù)據(jù)模型變?yōu)椴豢勺兊摹?strong>我們在最頂端將所有能更新狀態(tài)的函數(shù)串起來,把它們當(dāng)作一個(gè)原子(說成事務(wù)可能更容易明白)來對待。

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
);

注意:這個(gè)例子通過副作用去更新狀態(tài)。我對于此實(shí)際的理念模型是在每次的更新過程中返回下一個(gè)階段的狀態(tài)。當(dāng)然,不這樣做看起來要更簡單一點(diǎn),但是在以后我們最終還是會(huì)選擇改變這個(gè)例子采用的方式(因?yàn)楦弊饔玫娜秉c(diǎn)太多了)。

緩存

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

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
  ]);
}
列表/集合

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

??為了管理每個(gè)列表元素的狀態(tài),我們可以創(chuàng)建一個(gè)Map來管理每個(gè)特定的列表元素。

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);

注意:現(xiàn)在我們有多個(gè)不同的輸入傳遞給FancyNameBox。那會(huì)破壞我們上一節(jié)提到的緩存策略,因?yàn)槲覀円淮沃荒苡洃浺粋€(gè)值。(因?yàn)樯厦娴膍emoize函數(shù)的形參只有一個(gè))

續(xù)延

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

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

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

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
};

譯注:這里當(dāng)然可以采用

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

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

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

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

狀態(tài)映射

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

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);
緩存映射

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

??幸運(yùn)的是,在同一區(qū)域的UI通常是比較穩(wěn)定的,不會(huì)變化的。

??在這里我們依然可以采用像剛剛那種緩存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);
代數(shù)哲學(xué)

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

??有時(shí)候數(shù)據(jù)之間的依賴并不像抽象樹那樣整齊一致。例如,在布局算法中,在完整的確定所有字節(jié)點(diǎn)的位置之前,你需要知道各個(gè)子節(jié)點(diǎn)矩形區(qū)域的大小。

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理解不深,所以上面段就不翻譯了,以免誤導(dǎo)

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體系結(jié)構(gòu)

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

簡介

??React Fiber是一個(gè)正在進(jìn)行中的對React核心算法的重寫。它是過去兩年React團(tuán)隊(duì)研究成果的一個(gè)頂峰。

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

??其它關(guān)鍵的特性包括,1.擁有了暫停,中止以及當(dāng)有更新來臨的時(shí)候重新恢復(fù)工作的能力。2.不同的能力對于不同類型的更新分配不同的優(yōu)先級。3.新的并發(fā)原語。

關(guān)于本文檔

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

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

??請注意我并不是React團(tuán)隊(duì)的一員,也不具備足夠的權(quán)威。所以這并不是一份官方文檔。我已經(jīng)邀請了React團(tuán)隊(duì)的成員來對本文檔的準(zhǔn)確性進(jìn)行review。

??Fiber是一項(xiàng)還在進(jìn)行中的工作,在它完成前都很可能進(jìn)行重改。所以本文檔也是如此,隨著時(shí)間很可能發(fā)生變化。歡迎任何的建議。

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

準(zhǔn)備

??在繼續(xù)閱讀前,我強(qiáng)烈建議你確保自己對以下內(nèi)容已經(jīng)非常熟悉:

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

??Reconciliation - 對React的協(xié)調(diào)/調(diào)度算法的一個(gè)高度概括。

??React基礎(chǔ)理論概念 - 對React中的一些概念模型的抽象描述,第一次讀的時(shí)候可能不太能體會(huì)。沒關(guān)系,以后終會(huì)明白的。

??React設(shè)計(jì)原則 - 請注意其中的scheduling這一小節(jié),非常好的解釋了React Fiber。

回顧

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

什么是協(xié)調(diào)(reconciliation)

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

??update:數(shù)據(jù)的變化會(huì)導(dǎo)致渲染,通常這是setState的結(jié)果,最終會(huì)觸發(fā)重新渲染。

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

??事實(shí)上,每次變化都重新渲染整個(gè)app的方式只能工作在非常小的app上。在現(xiàn)實(shí)世界真正的app中,這在性能上花費(fèi)的代價(jià)太大了。React已經(jīng)在這方面做了優(yōu)化,在保持好性能的前提下創(chuàng)造出app重新渲染之后的樣子。絕大部分的優(yōu)化都屬于reconciliation這個(gè)過程的一部分。

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

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

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

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/82487.html

相關(guān)文章

  • ELSE 技術(shù)周刊(2017.12.11期)

    摘要:業(yè)界動(dòng)態(tài)發(fā)布版本,同時(shí)發(fā)布了版本以及首個(gè)穩(wěn)定版本的。程序人生如何用人類的方式進(jìn)行二關(guān)于如何在中進(jìn)行良好的溝通,避免陷入一些潛在的陷阱。技術(shù)周刊由小組出品,匯聚一周好文章,周刊原文。 業(yè)界動(dòng)態(tài) Angular 5.1 & More Now Available Angular發(fā)布5.1版本,同時(shí)發(fā)布了Angular CLI 1.6版本以及首個(gè)穩(wěn)定版本的Angular Material。CL...

    tylin 評論0 收藏0
  • 2017-07-12 前端日報(bào)

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

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

    摘要:它的主體特征是增量渲染能夠?qū)秩竟ぷ鞣指畛蓧K,并將其分散到多個(gè)幀中。實(shí)際上,這樣做可能會(huì)造成浪費(fèi),導(dǎo)致幀丟失并降低用戶體驗(yàn)。當(dāng)一個(gè)函數(shù)被執(zhí)行時(shí),一個(gè)新的堆??蚣鼙惶砑拥蕉褩V?。該堆??虮硎居稍摵瘮?shù)執(zhí)行的工作。 原文 react-fiber-architecture 介紹 React Fibre是React核心算法正在進(jìn)行的重新實(shí)現(xiàn)。它是React團(tuán)隊(duì)兩年多的研究成果。 React ...

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

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

    Jiavan 評論0 收藏0

發(fā)表評論

0條評論

lewif

|高級講師

TA的文章

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