成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從理念到LRU算法實(shí)現(xiàn),起底未來React異步開發(fā)方式

開發(fā) 前端 算法
React源碼內(nèi)部在實(shí)現(xiàn)不同模塊時用到了多種算法與數(shù)據(jù)機(jī)構(gòu)(比如調(diào)度器使用了小頂堆)。今天要聊的是數(shù)據(jù)緩存相關(guān)的LRU算法。

[[428240]]

大家好,我卡頌。

React源碼內(nèi)部在實(shí)現(xiàn)不同模塊時用到了多種算法與數(shù)據(jù)機(jī)構(gòu)(比如調(diào)度器使用了小頂堆)。

今天要聊的是數(shù)據(jù)緩存相關(guān)的LRU算法。內(nèi)容包含四方面:

  • 介紹一個React特性
  • 這個特性和LRU算法的關(guān)系
  • LRU算法的原理
  • React中LRU的實(shí)現(xiàn)

可以說是從入門到實(shí)現(xiàn)都會講到,所以內(nèi)容比較多,建議點(diǎn)個贊收藏慢慢食用。

一切的起點(diǎn):Suspense

在React16.6引入了Suspense和React.lazy,用來分割組件代碼。

對于如下代碼:

  1. import A from './A'
  2. import B from './B'
  3.  
  4. function App() { 
  5.   return ( 
  6.     <div> 
  7.       <A/> 
  8.       <B/> 
  9.     </div> 
  10.   ) 

經(jīng)由打包工具打包后生成:

chunk.js(包含A、B、App組件代碼)

對于首屏渲染,如果B組件不是必需的,可以將其代碼分割出去。只需要做如下修改:

  1. // 之前 
  2. import B from './B'
  3. // 之后 
  4. const B = React.lazy(() => import('./B')); 

經(jīng)由打包工具打包后生成:

  • chunk.js(包含A、App組件代碼)
  • b.js(包含B組件代碼)

這樣,B組件代碼會在首屏渲染時以jsonp的形式被請求,請求返回后再渲染。

為了在B請求返回之前顯示占位符,需要使用Suspense:

  1. // 之前,省略其余代碼 
  2. return ( 
  3.   <div> 
  4.     <A/> 
  5.     <B/> 
  6.   </div> 
  7. // 之后,省略其余代碼 
  8. return ( 
  9.   <div> 
  10.     <A/> 
  11.     <Suspense fallback={<div>loading...</div>}> 
  12.       <B/> 
  13.     </Suspense> 
  14.   </div> 

B請求返回前會渲染<div>loading.。.</div>作為占位符。

可見,Suspense的作用是:

在異步內(nèi)容返回前,顯示占位符(fallback屬性),返回后顯示內(nèi)容

再觀察下使用Suspense后組件返回的JSX結(jié)構(gòu),會發(fā)現(xiàn)一個很厲害的細(xì)節(jié):

  1. return ( 
  2.   <div> 
  3.     <A/> 
  4.     <Suspense fallback={<div>loading...</div>}> 
  5.       <B/> 
  6.     </Suspense> 
  7.   </div> 

從這段JSX中完全看不出組件B是異步渲染的!

同步和異步的區(qū)別在于:

  • 同步:開始 -> 結(jié)果
  • 異步:開始 -> 中間態(tài) -> 結(jié)果

Suspense可以將包裹在其中的子組件的中間態(tài)邏輯收斂到自己身上來處理(即Suspense的fallback屬性),所以子組件不需要區(qū)分同步、異步。

那么,能不能將Suspense的能力從React.lazy(異步請求組件代碼)推廣到所有異步操作呢?

答案是可以的。

resource的大作為

React倉庫是個monorepo,包含多個庫(比如react、react-dom),其中有個和Suspense結(jié)合的緩存庫 —— react-cache,讓我們看看他的用處。

假設(shè)我們有個請求用戶數(shù)據(jù)的方法fetchUser:

  1. const fetchUser = (id) => { 
  2.   return fetch(`xxx/user/${id}`).then
  3.     res => res.json() 
  4.   ) 
  5. }; 

經(jīng)由react-cache的createResource方法包裹,他就成為一個resource(資源):

  1. import {unstable_createResource as createResource} from 'react-cache'
  2.  
  3. const userResource = createResource(fetchUser); 

resource配合Suspense就能以同步的方式編寫異步請求數(shù)據(jù)的邏輯:

  1. function User({ userID }) { 
  2.   const data = userResource.read(userID); 
  3.    
  4.   return ( 
  5.     <div> 
  6.       <p>name: {data.name}</p> 
  7.       <p>age: {data.age}</p> 
  8.     </div> 
  9.   ) 

可以看到,userResource.read完全是同步寫法,其內(nèi)部會調(diào)用fetchUser。

背后的邏輯是:

  1. 首次調(diào)用userResource.read,會創(chuàng)建一個promise(即fetchUser的返回值)
  2. throw promise
  3. React內(nèi)部catch promise后,離User組件最近的祖先Suspense組件渲染fallback
  4. promise resolve后,User組件重新render
  5. 此時再調(diào)用userResource.read會返回resolve的結(jié)果(即fetchUser請求的數(shù)據(jù)),使用該數(shù)據(jù)繼續(xù)render

從步驟1和步驟5可以看出,對于一個請求,userResource.read可能會調(diào)用2次,即:

  • 第一次發(fā)送請求、返回promise
  • 第二次返回請求到的數(shù)據(jù)

所以userResource內(nèi)部需要緩存該promise的值,緩存的key就是userID:

  1. const data = userResource.read(userID); 

由于userID是User組件的props,所以當(dāng)User組件接收不同的userID時,userResource內(nèi)部需要緩存不同userID對應(yīng)的promise。

如果切換100個userID,就會緩存100個promise。顯然我們需要一個緩存清理算法,否則緩存占用會越來越多,直至溢出。

react-cache使用的緩存清理算法就是LRU算法。

LRU原理

LRU(Least recently used,最近最少使用)算法的核心思想是:

如果數(shù)據(jù)最近被訪問過,那么將來被訪問的幾率也更高

所以,越常被使用的數(shù)據(jù)權(quán)重越高。當(dāng)需要清理數(shù)據(jù)時,總是清理最不常使用的數(shù)據(jù)。

react-cache中LRU的實(shí)現(xiàn)

react-cache的實(shí)現(xiàn)包括兩部分:

  • 數(shù)據(jù)的存取
  • LRU算法實(shí)現(xiàn)

數(shù)據(jù)的存取

每個通過createResource創(chuàng)建的resource都有一個對應(yīng)map,其中:

  • 該map的key為resource.read(key)執(zhí)行時傳入的key
  • 該map的value為resource.read(key)執(zhí)行后返回的promise

在我們的userResource例子中,createResource執(zhí)行后會創(chuàng)建map:

  1. const userResource = createResource(fetchUser); 

userResource.read首次執(zhí)行后會在該map中設(shè)置一條userID為key,promise為value的數(shù)據(jù)(被稱為一個entry):

  1. const data = userResource.read(userID); 

要獲取某個entry,需要知道兩樣?xùn)|西:

  • entry對應(yīng)的key
  • entry所屬的resource

LRU算法實(shí)現(xiàn)

react-cache使用「雙向環(huán)狀鏈表」實(shí)現(xiàn)LRU算法,包含三個操作:插入、更新、刪除。

插入操作

首次執(zhí)行userResource.read(userID),得到entry0(簡稱n0),他會和自己形成環(huán)狀鏈表:

此時first(代表最高權(quán)重)指向n0。

改變userID props后,執(zhí)行userResource.read(userID),得到entry1(簡稱n1):

此時n0與n1形成環(huán)狀鏈表,first指向n1。

如果再插入n2,則如下所示:

可以看到,每當(dāng)加入一個新entry,first總是指向他,暗含了LRU中新的總是高權(quán)重的思想。

更新操作

每當(dāng)訪問一個entry時,由于他被使用,他的權(quán)重會被更新為最高。

對于如下n0 n1 n2,其中n2權(quán)重最高(first指向他):

當(dāng)再次訪問n1時,即調(diào)用如下函數(shù)時:

  1. userResource.read(n1對應(yīng)userID); 

n1會被賦予最高權(quán)重:

刪除操作

當(dāng)緩存數(shù)量超過設(shè)置的上限時,react-cache會清除權(quán)重較低的緩存。

對于如下n0 n1 n2,其中n2權(quán)重最高(first指向他):

如果緩存最大限制為1(即只緩存一個entry),則會迭代清理first.previous,直到緩存數(shù)量為1。

即首先清理n0:

接著清理n1:

每次清理后也會將map中對應(yīng)的entry刪掉。

完整LRU實(shí)現(xiàn)見react-cache LRU

總結(jié)

除了React.lazy、react-cache能結(jié)合Suspense,只要發(fā)揮想象力,任何異步流程都可以收斂到Suspense中,比如React Server Compontnt、流式SSR。

隨著底層React18在年底穩(wěn)定,相信未來這種同步寫法的開發(fā)模式會逐漸成為主流。

不管未來React開發(fā)出多少新奇玩意兒,底層永遠(yuǎn)是這些基礎(chǔ)算法與數(shù)據(jù)結(jié)構(gòu)。

真是樸素?zé)o華且枯燥......

 

責(zé)任編輯:姜華 來源: 魔術(shù)師卡頌
相關(guān)推薦

2023-06-15 10:53:57

2021-08-27 07:22:48

React組件前端

2014-04-24 11:49:42

DevOps自動化

2009-04-08 16:42:08

動態(tài)架構(gòu)DI智慧IT

2025-04-07 08:25:01

React復(fù)合組件組件模式

2013-03-06 09:58:39

開發(fā)方式軟件開發(fā)程序員

2015-09-22 09:30:28

2022-09-19 19:51:30

ReactuseEffect

2022-06-17 07:49:14

緩存LRU

2022-08-30 13:48:16

LinuxMySQL內(nèi)存

2009-11-23 09:27:00

PayPal支付接口

2014-03-14 14:04:29

AlloyDesign前端開發(fā)

2014-12-09 14:07:50

2020-02-19 19:18:02

緩存查詢速度淘汰算法

2017-03-06 16:43:04

無人駕駛Google X懸滑板

2010-12-01 09:04:59

PHP開發(fā)

2016-12-12 13:29:41

小程序小程序開發(fā)編程

2021-07-21 15:16:53

云原生阿里云云安全

2020-09-24 08:45:10

React架構(gòu)源碼

2015-07-29 10:31:16

Java緩存算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: aaaa日韩| 国产精品一区二区在线 | 91av视频在线观看 | 日韩a在线| 91亚洲精品国偷拍自产在线观看 | www.性色| 一区二区三区国产精品 | 久久综合888| 有码在线 | 毛片网在线观看 | 羞羞的视频在线观看 | 国产激情一区二区三区 | 日韩视频在线播放 | 午夜网| 午夜在线精品 | 国产美女自拍视频 | 超碰97人人人人人蜜桃 | 超碰成人av | 国产精品久久久久久吹潮 | 91精品国产综合久久久久蜜臀 | 天天影视亚洲综合网 | 国产精品视频久久 | 五月天婷婷综合 | 亚洲一区二区免费 | 成年人免费看 | 97色在线观看免费视频 | 超碰最新在线 | 九九热在线免费观看 | 久久久xxx| 欧美久操网 | 中文字幕一区二区三区精彩视频 | 欧洲av一区 | 日韩在线播放第一页 | 欧美日韩看片 | 国产亚洲第一页 | 在线观看国产www | 亚洲乱码国产乱码精品精98午夜 | 中文字幕精品一区二区三区精品 | 国产精品毛片无码 | 久久夜色精品国产 | 欧美日韩不卡合集视频 |