偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

React內(nèi)部是如何實(shí)現(xiàn)Cache方法的?

開(kāi)發(fā) 前端
React組件經(jīng)常render,如果在id不變的情況下,由于User組件render導(dǎo)致不斷發(fā)起請(qǐng)求,顯然是不合理的。這種情況下就需要cache方法。當(dāng)id不變時(shí),即使User組件反復(fù)render,fetch(id)都返回同一個(gè)值。本文來(lái)聊聊cache的源碼實(shí)現(xiàn)。

大家好,我卡頌。

前幾天寫(xiě)的一篇介紹use這個(gè)新hook的文章中聊到React原生實(shí)現(xiàn)了一個(gè)緩存函數(shù)的方法 —— cache。

對(duì)于如下代碼,被cache包裹的函數(shù),當(dāng)多次調(diào)用時(shí),如果傳參不變,會(huì)始終返回緩存值:

const cacheFn = cache(fn);
cacheFn(1, 2, 3);
// 不會(huì)執(zhí)行fn,直接返回緩存值
cacheFn(1, 2, 3);

React內(nèi)為什么需要cache方法呢?考慮如下組件:

const fetch = cache(fetchUserData);

function User({id}) {
const {name} = use(fetch(id));

return <p>{name}</p>;
}

User組件會(huì)根據(jù)用戶(hù)id請(qǐng)求用戶(hù)數(shù)據(jù),并渲染用戶(hù)名。

如果id改變,那么fetch方法重新發(fā)起請(qǐng)求是正常邏輯。

但是,React組件經(jīng)常render,如果在id不變的情況下,由于User組件render導(dǎo)致不斷發(fā)起請(qǐng)求,顯然是不合理的。

所以,這種情況下就需要cache方法。當(dāng)id不變時(shí),即使User組件反復(fù)render,fetch(id)都返回同一個(gè)值。

本文來(lái)聊聊cache的源碼實(shí)現(xiàn)。

分析實(shí)現(xiàn)思路

整個(gè)方法實(shí)現(xiàn)一共有64行代碼,首先我們來(lái)分析下實(shí)現(xiàn)要點(diǎn)。

如果參數(shù)不變,則使用緩存的值。這意味著我們需要處理:

參數(shù)的順序

舉個(gè)例子,當(dāng)參數(shù)順序變了,不使用緩存值:

const cacheFn = cache(fn);
cacheFn(1, 2, 3);
// 不使用緩存值
cacheFn(3, 2, 1);

區(qū)別處理引用類(lèi)型、原始類(lèi)型參數(shù)

舉個(gè)例子,當(dāng)同一位置的參數(shù)傳遞了同一個(gè)引用類(lèi)型值,則返回緩存值:

const cacheFn = cache(fn);
const obj = {};
cacheFn(1, obj, 3);
// 返回緩存值
cacheFn(1, obj, 3);

當(dāng)同一位置的參數(shù)傳遞了不同引用類(lèi)型值,則不返回緩存值:

const cacheFn = cache(fn);
const obj = {};
cacheFn(1, obj, 3);
// 不返回緩存值
cacheFn(1, {}, 3);

緩存的垃圾回收

緩存數(shù)據(jù)時(shí),要注意「緩存失效但是引用的數(shù)據(jù)沒(méi)有釋放」造成的內(nèi)存泄漏問(wèn)題。

所以,對(duì)于引用類(lèi)型數(shù)據(jù),可以使用WeakMap保存。

對(duì)于原始類(lèi)型數(shù)據(jù),可以使用Map保存。

WeakMap與Map的區(qū)別在于 —— 在WeakMap中,key到他對(duì)應(yīng)的value是弱引用。這意味著當(dāng)沒(méi)有其他數(shù)據(jù)引用這個(gè)key時(shí),他可以被垃圾回收。而在Map中,key到value是強(qiáng)引用,即使沒(méi)有其他數(shù)據(jù)引用這個(gè)key,他也不會(huì)被垃圾回收。

實(shí)現(xiàn)原理

本文不會(huì)介紹具體的代碼實(shí)現(xiàn)(大段貼代碼讓人看起來(lái)頭疼)。

我會(huì)用示例圖講解實(shí)現(xiàn)原理。了解原理后,如果你對(duì)實(shí)現(xiàn)細(xì)節(jié)感興趣,可以參考:

  • cache的源碼實(shí)現(xiàn)PR[1]
  • cache的在線示例[2]

對(duì)于如下代碼:

const cacheFn = cache(fn);
const obj = {};
cacheFn(1, obj, 3);

cacheFn的每個(gè)傳參,對(duì)應(yīng)cache內(nèi)部的一個(gè)cacheNode節(jié)點(diǎn):

// CacheNode構(gòu)造函數(shù)
function createCacheNode<T>(): CacheNode<T> {
return {
s: UNTERMINATED,
v: undefined,
o: null,
p: null
};
}

字段的意義如下:

  • s:cacheNode的緩存狀態(tài),有 未中止/中止/發(fā)生錯(cuò)誤 3種狀態(tài)。
  • v:cacheNode緩存的值。
  • o:緩存的引用類(lèi)型值。
  • p:緩存的原始類(lèi)型值。

上述cacheFn執(zhí)行后會(huì)生成如下cacheNode鏈?zhǔn)浇Y(jié)構(gòu):

圖片

讓我們看看這個(gè)鏈?zhǔn)浇Y(jié)構(gòu)如何解決文章開(kāi)篇提到的3個(gè)問(wèn)題。

如何解決參數(shù)的順序?

可以看到,上圖中最后一個(gè)cacheNode節(jié)點(diǎn)的狀態(tài)(cacheNode.s)為「中止」。

如果后續(xù)執(zhí)行cacheFn傳入相同的參數(shù),則會(huì)復(fù)用緩存的cacheNode節(jié)點(diǎn)。

如果所有傳參都相同,那么會(huì)復(fù)用完整的cacheNode鏈,此時(shí)最后一個(gè)cacheNode節(jié)點(diǎn)為「中止」?fàn)顟B(tài),則不需要重新執(zhí)行cacheFn方法計(jì)算返回值,而是直接返回緩存的值(cacheNode.v)。

如果后續(xù)執(zhí)行cacheFn,傳入新的參數(shù),則前后的cacheNode鏈不會(huì)一致。

比如:

// 第一次
cacheFn(1, obj, 3);
// 第二次
cacheFn(1, 3, obj);

則第二次生成的cacheNode鏈中,第二個(gè)節(jié)點(diǎn)就與之前不同(之前obj,之后3),則后續(xù)cacheNode節(jié)點(diǎn)也不會(huì)相同。

圖片

通過(guò)這種鏈?zhǔn)浇Y(jié)構(gòu),保證了只有當(dāng)所有參數(shù)保持一致,才能返回緩存的值。否則將重新執(zhí)行函數(shù),并緩存新的返回值與cacheNode鏈。

如何處理引用類(lèi)型值

可以從圖中發(fā)現(xiàn),對(duì)于引用類(lèi)型參數(shù)(比如示例中的obj),對(duì)應(yīng)一個(gè)weakMap節(jié)點(diǎn)。

這不僅意味著當(dāng)沒(méi)有其他數(shù)據(jù)引用他時(shí),這個(gè)cacheNode節(jié)點(diǎn)能夠釋放內(nèi)存,同時(shí)也意味著這個(gè)cacheNode之后的cacheNode鏈會(huì)斷掉,他們占用的內(nèi)存也會(huì)釋放。

而原始類(lèi)型值不存在這樣的問(wèn)題,從圖中可以發(fā)現(xiàn),原始類(lèi)型值對(duì)應(yīng)一個(gè)map節(jié)點(diǎn)。

總結(jié)

cache方法是React內(nèi)部實(shí)現(xiàn),未來(lái)會(huì)暴露給開(kāi)發(fā)者使用的緩存方法,可以緩存任意函數(shù)。

當(dāng)多次執(zhí)行并傳遞相同的參數(shù)給cache包裹的函數(shù)時(shí),后續(xù)執(zhí)行會(huì)返回緩存的值。

這是為了應(yīng)對(duì)「某些函數(shù)需要在React組件多次render間返回穩(wěn)定的值」的場(chǎng)景。

比如:對(duì)于相同的傳參,請(qǐng)求數(shù)據(jù)的函數(shù)返回同一個(gè)promise。

cache的實(shí)現(xiàn)方式是 —— 基于傳參,構(gòu)造一條cacheNode鏈,傳參的穩(wěn)定對(duì)應(yīng)了鏈表的穩(wěn)定,并最終對(duì)應(yīng)了返回值的穩(wěn)定。

參考資料

[1]cache的源碼實(shí)現(xiàn)PR:https://github.com/sebmarkbage/react/blob/ecdf734d1aa73d9f5f09f5a8e7fa5685f5f1bd29/packages/react/src/ReactCache.js。

[2]cache的在線示例:https://codesandbox.io/s/amazing-leaf-viq4q7?file=/src/cache.js。

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

2021-08-19 16:56:37

Python內(nèi)存開(kāi)發(fā)

2023-11-23 19:30:35

Python編程語(yǔ)言

2020-02-12 15:08:41

KVM內(nèi)部運(yùn)作

2022-08-22 16:23:11

React特性

2023-10-07 08:41:42

JavaJVM

2023-05-05 18:38:33

多級(jí)緩存Caffeine開(kāi)發(fā)

2022-04-14 09:01:39

React源碼Flow

2022-07-27 07:32:28

Debug版本arthas

2019-10-08 11:10:18

React自動(dòng)保存前端

2023-04-06 09:41:00

React 組件重渲染

2022-12-23 08:34:30

HookReact

2022-05-15 22:08:58

ReactHookdebounce

2021-09-17 12:50:10

MySQL數(shù)據(jù)庫(kù)ACID

2022-03-11 10:23:02

React性能優(yōu)化

2023-05-31 07:29:46

2022-12-07 11:21:30

Reactdiff

2023-12-05 15:58:06

React開(kāi)發(fā)

2020-10-21 08:38:47

React源碼

2024-11-05 15:02:41

2022-08-02 11:27:25

RabbitMQ消息路由
點(diǎn)贊
收藏

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