解析Twitter前端架构 学习复杂场景数据设计

前几天刷Twitter,发现Nicolas(Engineering at @twitter. Technical Lead for Twitter Lite)发布了这么一条推文:

twitter.jpeg

大体意思就是Twitter前端经过重构,已经完全迁移到React+Redux+PWA技术栈了,后端也使用了nodeJS,实现了“前端一统天下”,lol。

听到这个消息之后,我觉得去深挖一下Twitter的Redux store组织架构,将会非常有意思。
这对于在复杂场景下的前端数据学习,以及React、Redux数据流设计十分有意义。

因为,在Redux数据流框架的思想下,对于数据的处理和分配完全由前端掌握。
前端数据如何设计,设计的功力如何直接完全决定整个项目的开发进度以及代码强健性,甚至还决定着页面的性能。

本文将剖析Twitter前端数据结构层次,如果你对React技术栈不是很了解,也不妨碍阅读;同样,如果你对这套技术栈有兴趣的话,欢迎参看我的其他类似文章:

欢迎关注我的主页,更多技术文章不再错过。

本文主体内容翻译自Ryan Johnson的文章:Dissecting Twitter’s Redux Store,笔者进行了一定程度的拓展。

准备工作

想要看Redux store的前提是你需要配有React Developer Tools (RDT),在RDT tab中选中应用根节点。
确保选中之后,在console面板中输入:

// $r is a shortcut that references the selected element in RDT
$r.store.getState();

接下来,我们就可以看到Redux数据树,就像图中所示:

数据结构

设计分析

我建议大家花些时间对每个不同的state进行展开,并加以学习。但在这篇文章中,由于篇幅所限,我会挑选并深挖:

  • entities/tweets和
  • homeTimeline

两个最主要也是最核心的state进行剖析。这两个states包含了一条tweet的所有关联数据。

一条tweet,就像下图中我所发的:

推文举例

一条tweet内容的数据信息全部存储在entities/tweets/entities中,entities/tweets/entities可以理解为一个normalized的data table,它存储了所有tweets推文的信息;
在这个table中,每一条tweet都是一个键值对类型的js object:key为该条tweet的id,value为该条tweet的数据,也是一个js object。

下图中,我将第一条tweet展开,方便大家一探究竟:

推文设计.png

了解了tweet存储结构,我们接下来看一下Twitter首页的timeline结构。
直观上,timeline一定包含了个人主页展示推文的信息。通过tweet id和刚才介绍过的entities/tweets/entities中的tweet相匹配,并最终加以在timeline上展示。
如下图:

timeline数据结构

每个用户的首页timeline信息可homeTimelines/timeline找到。首页timeline展示的顺序,则按照timeline这个数组的顺序。也就是说,timeline数组index为0的条目,就是你在首页timeline上看到的第一条tweet;

重要的话再说一遍:
首页timeline上的每条tweet,都有一个唯一的id,这个id和上面介绍的,存储在entities/tweets/entities之中的tweet id相匹配。

看到这里,你也许会感叹:

“This is pretty much normalizing state shape 101 from Dan Abramov!”

没错,这样的范式也是Redux所推崇的,完全的扁平化设计带来的开发体验和性能提升是无与伦比的。

当然,你可能会问为什么Redux设计哲学,包括Twitter都在推崇扁平化的数据结构呢?
这个问题建议参考:Redux core concepts,这里讲的非常清晰,被收录在Redux core concepts中,强烈建议阅读。
如果您英语吃力,可以留言与我交流,就不再展开了。

继续言归正传,我们来讨论一下滚动时的异步请求设计。
首页timeline加载新tweets方式有两种:

  • 上拉加载 track tweets by top
  • 下滑加载 track tweets by bottom

第一种用于拉取更新的tweets,第二种用于拉取更旧的tweets;比如你新发了一条tweet,就要上拉,方可显示在timeline上;如果没有最新的,向下滑动到底部后,自动加载时间上更早的tweets。
用一个等式来表达:

top = new tweets,
and
bottom = older tweets

这种情况下,homeTimelines下的lastFetch.bottom和lastFetch.top,分别为时间戳,记录最后一次更新数据的信息(上拉和下滑)。

  • lastFetch.bottom: 记录最后一次向下滑动而更新数据的信息;
  • lastFetch.top: 记录最后一次下上拉取而更新数据的信息;

同时,
cursor.bottom和cursor.top值分别为一个tweet id,表示当前timeline上,最上边和最底部分别是哪一条tweet。

  • cursor.bottom: 记录屏幕最底部tweet ID;
  • cursor.top: 记录屏幕最顶部tweet ID;

同时, homeTimelines里面还记录了isLoadingDirections.bottom和isLoadingDirections.top来表示数据加载的触发源头。

如图:

记录信息.png

最后一个非常有意思的是,entities下除了存在entities/tweets之外,还分别有cards, lists and users;

  • entities/tweets
  • entities/cards
  • entities/lists
  • entities/users

来表示不同的推文特性。

当你打开这其余三项的时候,会发现这三项与entities/tweets保持在相同的结构,他们都有一个fetchStatus的data table,key为tweet id, value为加载状态,据统计一共有一下几种:

  • ‘none’;
  • ‘loading’;
  • ‘loaded’;
  • ‘failed’.
状态截图

这几种状态的设置无外乎这么几个目的:

  • 保证在loading状态或loaded的tweet不会再发送请求给server;
  • 在未加载完时,可以显示加载动画或者展位图;
  • 在加载失败时,可以显示失败提示或者在此请求时进行补救。

总结

本文分析了Twitter在采用Redux架构下的数据设计结构,在一个复杂的场景下,希望引起读者对redux能有一个更深入的认识。

本文主体内容翻译自Ryan Johnson的文章:Dissecting Twitter’s Redux Store,笔者进行了一定程度的拓展。

Happy coding!

PS: 作者Github仓库,欢迎通过代码各种形式交流。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,796评论 25 707
  • RxSwift_v1.0笔记——23 MVVM with RxSwift RxSwift是一个很大的话题,本书之前...
    大灰很阅读 1,812评论 7 6
  • 聚焦在 Twitter 上关于Apache Spark的数据,目标是准备将来用于机器学习和流式处理应用的数据。 ...
    abel_cao阅读 2,697评论 1 12
  • JUSTINMIND http://www.justinmind.com/ SKETCH/MIRROR http:...
    kuileishi阅读 226评论 0 1
  • 今天看了一个视频关于拖延症的介绍,所以来总结下。 生活中,自己总是对什么都感兴趣,什么都想做,但是又什么都没做~ ...
    雨霁彩彻阅读 154评论 0 0