Closed yuxino closed 3 years ago
github
timeline
swr
now
shuding
CSAPP
GEEK
vue
release
vueposu
SO LET'S GO
SWR
cache-control
const { data, error, isValidating } = useSWR('/api/user', fetcher)
data
error
isValidating
正在验证
isLoading
stale-while-revalidate
revalidate
第一个亮点我认为是 window.focus吧。 比如我们把鼠标移出网页,一阵子之后回来,swr非常的智能,会帮我们自动调用 revalidate,来尝试获取一次最新的数据,更新页面。但这个其实是把双刃剑,有时候不太合适。但是可以关,默认是打开的。
window.focus
第二个两点就是 cache。 有人说前端 除了 cache 就是 在处理 cache的问题。 可见 cache 在前端里面是如此的重要。举个例子吧,在线计算充值金额,众所周知,前端虽然可以算,你也可以算,只要你勇于背锅。挑战绩效拿最低。以及出了事,卷普滚蛋的心态,你可以接,不然还是让服务端算吧,计算金额其实是个蛮频繁的操作,前端需要做好debounce或者throttle的处理避免多余的网络请求,最好是debounce吧。
cache
debounce
throttle
origin
第三个点,我一直认为它可以作为 state manager, 但不单单是 state manager, 更加贴切的是 remote state manager。它可以作为 redux 甚至一些东西的代替品。 非常 awesome ,这个特性,可能是无心插柳柳成荫吧。
state manager
remote state manager
redux
awesome
第四个点,轮询,不用写的多复杂他能帮你做好这件事。
第五点,滚动条位置恢复
第六点,线性的代码逻辑
这个图表示的是常见的数据依赖的请求图示
我们看到了这里有些请求时互相依赖的,有些是不依赖的,对于依赖的我们可以用await,写出类似这样的代码(伪)。
await
const res1 = await request(...); const res2 = await request(res1); const res3 = await request(...)
但是这会导致问题,请求不是并行的,会阻塞所有的请求。有些并不是依赖这个请求的请求也给阻塞了,比如res3,但是 swr 可以帮你避免这个问题,最大程度的进行并行的请求,写出类似这样的代码(伪)。
res3
const res1 = useSWR(...); const res2 = useSWR(res1); const res3 = useSWR(...)
尽最大可能让所有请求都是并行的,而互相依赖的请求保持顺序执行。
第七点,状态的优化。在SWR里面比较用心的一点是状态都是useRef的,也就是说不出意外不会乱更新视图,只要你没用到,大佬通过这一段控制依赖收集。如果用到了就设置成true,设置成true的状态会在dispatch的时候触发 rerender。但是在vue里面不用做这个事情,vue帮忙做了。
useRef
true
dispatch
第八点,SWR会对俩次的结果进行[深比较](https://github.com/epoberezkin/fast-deep-equal),这样可以避免重复的视图更新。
[深比较](https://github.com/epoberezkin/fast-deep-equal)
muate 和 boundMutate 以及 revalidate 的关系
muate
boundMutate
boundMutate 是源码里面的称呼。是 useSWR 调用之后返回的那个 mutate,这里为了做区分特意写了出来。
useSWR
mutate
mutate('xxx') 和 const { mutate } = useSWR('xxx'),这俩是等价的。
mutate('xxx')
const { mutate } = useSWR('xxx')
直觉上来说 mutate 就是手动改变状态,事实上它也确实是这样子。然后就会写出这样的代码,点击C2的时候变化内容。
import useSWR from "swr"; let id = 0; const fetcher = () => new Promise((res) => { setTimeout(() => res(id++), 200); }); export default function App() { const C1 = () => { const { data } = useSWR("fetch", fetcher); return <span>{data}</span>; }; const C2 = () => { const { data, mutate } = useSWR("fetch", fetcher); return <span onClick={() => mutate("x", false)}>{data}</span>; }; return ( <div> <C1 /> || <C2 /> </div> ); }
那么实际上点击的时候,会有个速度非常快的变化,先变成了x,再变成2。因为不传 mutate的第二个参数时候, SWR 会默认进行一次 revalidate 。 如果想保持为 x,那就再传一个参数mutate("x", false),这样表示不会自动调用revalidate了。
x
mutate("x", false)
首先第一个参数可以传方法,我也没咋看文档一开始,我吼兴奋啊,难道可以写fetcher, 帮我获取数据,然后自动缓存,然鹅刚写就报错了,结果只能返回 string, 说明这压根就不是这么用的,而且只是方法的话,估计也算不出稳定的 key,无法做到缓存这么一说。
fetcher
string
key
第二个,如果你有两个同名的key,你分别给他们传不一样的 options。他俩分别会产生俩种不一样的调用 revalidate 的行为。如果是俩都写了 refreshInterval 可能会让你抓狂。hmmm, 如果同事俩个时间差在 2ms 内,只会调用同一个,看起来,只是看起来,但是如果俩个时间差在 2ms以上,两个都会给同时调用。还有各种奇奇怪的情况,反正同个 key 的话抽出来,不要传不一样的 options 不然会导致一些奇怪的问题。
options
refreshInterval
2ms
背景
github
的timeline
,不知道哪个人点了star吧。因为swr
是来自now
这个team,于是有点感兴趣。了解了一下背景,还是国内大佬shuding
的作品。大佬非常有意思,造的东西都很惊艳,比如Y86处理器这个项目,我一直觉得CSAPP
并没有那么有趣吧,也不是,并没有那么那么内啥,但是大佬让我看到了另一面,一个枯燥的编译器指令集在前端页面上也能发光发热,打造出如此赛博朋克的感觉,这是真正喜欢技术的人才能办到的事情,也是我追求的GEEK
的感觉吧,沉浸在自己觉得有意义的事情里,是非常容易让人感到满足与骄傲的。vue
版本的swr
,所以我们必须去理解为什么swr
要这么做,它这么做会导致什么问题,以及我们是否有办法在我们release
第一个vueposu
的版本的时候避免掉这些问题,SO LET'S GO
, 让我们来探索SWR
。cache-control
有任何的交互。const { data, error, isValidating } = useSWR('/api/user', fetcher)
data
和error
很好理解吧,就是数据和异常isValidating
是什么呢? 翻译一下正在验证
,正在验证
是什么鬼,肯定不对,但是它的行为类似isLoading
,我们也可以完全理解它就是我们平时说的isLoading
。isValidating
是怎么来的呢。stale-while-revalidate
的最后一个单词。revalidate
就是获取数据在swr
里。那么很自然,获取数据就是isValidating
,大概是根据revalidate
变种过来的。亮点
第一个亮点我认为是
window.focus
吧。 比如我们把鼠标移出网页,一阵子之后回来,swr
非常的智能,会帮我们自动调用revalidate
,来尝试获取一次最新的数据,更新页面。但这个其实是把双刃剑,有时候不太合适。但是可以关,默认是打开的。第二个两点就是
cache
。 有人说前端 除了cache
就是 在处理cache
的问题。 可见cache
在前端里面是如此的重要。举个例子吧,在线计算充值金额,众所周知,前端虽然可以算,你也可以算,只要你勇于背锅。挑战绩效拿最低。以及出了事,卷普滚蛋的心态,你可以接,不然还是让服务端算吧,计算金额其实是个蛮频繁的操作,前端需要做好debounce
或者throttle
的处理避免多余的网络请求,最好是debounce
吧。origin
的字段,代表原来的充值金额origin
和你输入框的金额是否一样,一样的话就显示那个结果,不一样就显示菊花就好了。swr
,真没必要这么做。它能帮你避过这个坑。swr
能够处理这种竞态问题,只会以最后一个发起的结果为准。第三个点,我一直认为它可以作为
state manager
, 但不单单是state manager
, 更加贴切的是remote state manager
。它可以作为redux
甚至一些东西的代替品。 非常awesome
,这个特性,可能是无心插柳柳成荫吧。第四个点,轮询,不用写的多复杂他能帮你做好这件事。
第五点,滚动条位置恢复
第六点,线性的代码逻辑
这个图表示的是常见的数据依赖的请求图示
我们看到了这里有些请求时互相依赖的,有些是不依赖的,对于依赖的我们可以用
await
,写出类似这样的代码(伪)。但是这会导致问题,请求不是并行的,会阻塞所有的请求。有些并不是依赖这个请求的请求也给阻塞了,比如
res3
,但是swr
可以帮你避免这个问题,最大程度的进行并行的请求,写出类似这样的代码(伪)。尽最大可能让所有请求都是并行的,而互相依赖的请求保持顺序执行。
第七点,状态的优化。在
SWR
里面比较用心的一点是状态都是useRef
的,也就是说不出意外不会乱更新视图,只要你没用到,大佬通过这一段控制依赖收集。如果用到了就设置成true
,设置成true
的状态会在dispatch
的时候触发 rerender。但是在vue
里面不用做这个事情,vue
帮忙做了。第八点,
SWR
会对俩次的结果进行[深比较](https://github.com/epoberezkin/fast-deep-equal)
,这样可以避免重复的视图更新。设计上的思考
muate
和boundMutate
以及revalidate
的关系boundMutate
是源码里面的称呼。是useSWR
调用之后返回的那个mutate
,这里为了做区分特意写了出来。mutate('xxx')
和const { mutate } = useSWR('xxx')
,这俩是等价的。直觉上来说
mutate
就是手动改变状态,事实上它也确实是这样子。然后就会写出这样的代码,点击C2的时候变化内容。那么实际上点击的时候,会有个速度非常快的变化,先变成了
x
,再变成2。因为不传mutate
的第二个参数时候,SWR
会默认进行一次revalidate
。 如果想保持为x
,那就再传一个参数mutate("x", false)
,这样表示不会自动调用revalidate
了。比较操蛋的事情
首先第一个参数可以传方法,我也没咋看文档一开始,我吼兴奋啊,难道可以写
fetcher
, 帮我获取数据,然后自动缓存,然鹅刚写就报错了,结果只能返回string
, 说明这压根就不是这么用的,而且只是方法的话,估计也算不出稳定的key
,无法做到缓存这么一说。第二个,如果你有两个同名的
key
,你分别给他们传不一样的options
。他俩分别会产生俩种不一样的调用revalidate
的行为。如果是俩都写了refreshInterval
可能会让你抓狂。hmmm, 如果同事俩个时间差在2ms
内,只会调用同一个,看起来,只是看起来,但是如果俩个时间差在2ms
以上,两个都会给同时调用。还有各种奇奇怪的情况,反正同个key
的话抽出来,不要传不一样的options
不然会导致一些奇怪的问题。