0到1:閒魚高複雜度高性能社區圈子開發實錄

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作爲一款承載着「基於興趣聚集同好人羣」的社區型產品,相較於常規導購型產品來說,在業務複雜度、交互複雜度、性能體驗穩定性要求上都要高出許多,像"},{"type":"text","marks":[{"type":"strong"}],"text":"多角色區分"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"strong"}],"text":"嵌套滾動"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"strong"}],"text":"多形態 Feeds 無限加載"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"strong"}],"text":"顏文字等特殊字符處理"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"strong"}],"text":"頁面直開"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"strong"}],"text":"視頻播控"},{"type":"text","text":"等場景都是導購場景很少遇到的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文將圍繞着會玩圈子的前端設計、開發過程中遇到的典型問題進行介紹。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"關鍵設計"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/f3\/f34ad23d6574658845da1490be5abc4c.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖爲會玩圈子的設計大圖,可以看到整體的業務邏輯相對較爲複雜。並且由於應用中存在"},{"type":"text","marks":[{"type":"strong"}],"text":"多種角色狀態"},{"type":"text","text":",不同角色的用戶展示界面和操作邏輯也有差異點存在,前端同學進行開發上手的成本較高。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了降低前端同學在開發過程中對於全局業務理解的成本,減少溝通中信息傳遞容易遺漏的問題。我們在設計之初首先進行了最小模塊的拆分工作。以模塊維度來分配相應的工作,將模塊間存在數據共享和數據通信行爲進行梳理拆解,以最優方式來分配數據狀態維護的最小閉環,降低組件間耦合度。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"模塊拆分"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在此處定義的模塊不是前端日常開發中所講的模塊組件拆分,而是能夠獨立閉環自成體系的一個業務單元。這樣在項目過程中除了部分組件間數據傳遞需要做預先約定外,前端同學僅僅只需要專注於自己所負責的交互場景即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b4\/b47c23dbd097465b1836523c32218324.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/07\/0749be5ca25217e8da3767c3222048f0.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以圈子模塊主頁爲例,根據設計稿我們將它拆分爲了三個獨立的業務模塊:"},{"type":"text","marks":[{"type":"strong"}],"text":"圈子信息模塊、信息流模塊和浮層組件模塊"},{"type":"text","text":",他們無論從功能上還是展示上都完全不同。"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圈子信息模塊: 偏展示型模塊。交互較少,根據業務數據展示相應的信息模塊內容,需要根據用戶當前的身份展示不同類型的模塊組件,並且可以根據當前用戶的身份來進行權限校驗,在未符合時進行友好Tip提示的能力。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"信息流模塊:偏交互型模塊。需要支持多個列表在Tab下嵌套滾動的能力,模塊本身需要維護用戶關注狀態表、黑名單篩選表和視頻播放列表,方便模塊中的子組件進行數據共享。並且列表具備單排流和瀑布流兩種佈局模式,列表內元素存在商品、帖子內容兩種類型卡片。支持評論、點贊查看原圖、視頻播放、觸發浮層等多種交互能力。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"浮層模塊:通用型模塊。允許開發者根據業務需求註冊相應的模塊組件,並且允許配置相應的展示位置、動畫效果和圖層index"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"狀態值拆分"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於在圈子中有非常多需要共享信息的場景存在,例如用戶相關數據、圈子基礎信息等,僅僅只是基於業務模塊閉環來拆分狀態在此處就不適合了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此在完成模塊拆分之後我們對圈子主頁的狀態數據進行了梳理,根據組件最小渲染原則來對狀態進行相應的拆分,如下圖所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2a\/2a034cb0f7944b98706bdd28f40b8771.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"全局狀態"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖,對於有共享訴求的狀態變量,我們優先將這些狀態值彙總到一起以方便統一處理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但由於是C端場景,交互複雜度不高並且考慮到資源包的大小會對用戶體驗有一定影響。此處的全局狀態的管理方案我們選擇了直接使用Rax原生的"},{"type":"codeinline","content":[{"type":"text","text":"useReducer + useContext"}]},{"type":"text","text":"來進行處理,並將獲取對應實例"},{"type":"codeinline","content":[{"type":"text","text":"context"}]},{"type":"text","text":" 的方法Hooks化以方便開發同學使用,簡單demo代碼如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/80\/80c011de8687400bb1bb4d624ea51d62.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"業務組件狀態"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於非共享型的數據,則要求放到業務模塊中組件渲染影響最小的容器層來進行維護,以單排流的帖子列表爲例:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"卡片的初始數據通過props形式傳入,單一帖子的交互性數據都保留在帖子元素組件一層來維護。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"列表容器中除了基礎狀態信息外,僅僅只做視頻播放的控制,不額外觸發容器級的重渲染。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"實施調優"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在多個業務模塊進行組合調試的過程中,我們發現交互體驗依然有許多不盡人意的問題點:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"展示模塊過多的情況下,如果在多個Tab下進行數據加載切換過後整個頁面的交互會出現明顯的卡頓感:比如點擊彈出浮層會有明顯的等待時延,翻頁切換Tab時對應的下標移動會不同步。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"浮層容器中註冊的部分組件由於依賴共享變量,在共享變量變化時也會觸發不必要的重渲染:效果爲會跟着閃動一下。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"網絡狀況不穩定的情況,頁面展示不夠友好的;從用戶點擊路由跳轉到首屏頁面展示的等待時間過於明顯,與我們要求的頁面直開效果相差甚遠。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"減少Context.Provider重渲染"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a3\/a3b35e386a149e605924bcd978aa1336.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用Context儘管可以提升狀態值傳遞的便捷性,但是伴隨的問題也相當明顯:每一次狀態值更新變化都會觸發整個Context.Provider和下面的子組件重新渲染。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這與我們預期的渲染流程不一致,畢竟我可能只是調整了一個"},{"type":"codeinline","content":[{"type":"text","text":"CircleHeader"}]},{"type":"text","text":"組件所依賴的值,沒必要底下"},{"type":"codeinline","content":[{"type":"text","text":"CircleSlider"}]},{"type":"text","text":"組件及其中的列表組件都需要跟着做調整渲染,這個代價是我們無法接受的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過在社區中尋找相應的解決方案,我們發現還是有一定技巧來解決這個問題的:"},{"type":"codeinline","content":[{"type":"text","text":"Context.Provider"}]},{"type":"text","text":"其實組件也保持着"},{"type":"codeinline","content":[{"type":"text","text":"Rax"}]},{"type":"text","text":"組件的一致規則:"},{"type":"codeinline","content":[{"type":"text","text":"props.children"}]},{"type":"text","text":"作爲傳入屬性,它如果保持不變就不會觸發值diff,進而也就不會出現重渲染的問題了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那如何才能做到讓"},{"type":"codeinline","content":[{"type":"text","text":"Provider"}]},{"type":"text","text":"不會由於"},{"type":"codeinline","content":[{"type":"text","text":"props.children"}]},{"type":"text","text":"的變化產生重渲染呢?通過社區提供的資料,我們發現每次執行的都是JSX轉義後的"},{"type":"codeinline","content":[{"type":"text","text":"createElement(xxx)"}]},{"type":"text","text":"。由於每次執行產生的子組件都不一致,所以會導致不必要的重渲染。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲此我們將"},{"type":"codeinline","content":[{"type":"text","text":"Context.Provider"}]},{"type":"text","text":"單獨拆分成爲一個專門用於傳狀態值的高階組件,將子組件以"},{"type":"codeinline","content":[{"type":"text","text":"props.children"}]},{"type":"text","text":"的形式傳入:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ea\/ea5778c9cf52252396721f63fe4e539a.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過這種方式,我們將CircleApp變爲了Stateless Component。只有在首次初始化組件時進行渲染,之後Provider值變化時頁不會重新導致GlobalContextProvider執行createElement(CircleApp``)來重新創建組件實例了,減少不必要的js執行。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"調整組件結構"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/cf\/cfd0510f3c4177a4871e6a1076fe2ce2.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖可以看到在圈子中存在較多彈出浮層組件的場景,在初版設計過程中考慮到浮層組件由於也需要使用到全局共享變量。因此在設計組件結構之初,將浮層容器組件放到了全局共享變量的GlobalContextProvider組件之內。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但在實際體驗過後發現,儘管對於內部的浮層組件獲取共享變量較便利了,但反饋出來的問題也相當明顯:在使用中低端機型時,如果頁面加載的數據過多後會出現明顯的延遲感。並且浮層組件僅僅在真實展示的時候才需要用到相應的狀態值,非展示時其實不需要關係這些數據的具體內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/00\/00d5e393599b35c3ad4357ae708c4496.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲此我們調整了浮層容器組件和主頁常駐組件的層級結構,如上圖所示:將常駐組件容器和層容器由原來的嵌套結構優化爲了並行結構,兩組件之間的數據通信通過方法調用來觸發。這樣調整之後優點相對比較明顯:首先浮層組件可以更加通用、複用性更強。所有所需參數都是通過傳參的方式傳入,不需要再強依賴全局共享狀態,對於開發同學來說維護起來的成本更低。其次因爲減少對共享狀態值的依賴,子組件不必要的重渲染也都得到了優化。對於中低端機型也能提供相對更好的互動體驗。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"首屏體驗優化 + 容災機制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在去年下半年的體驗優化升級戰役中閒魚的前端頁面體驗都有了很大的提升:頁面首屏等待時間大幅度降低、內容展示更加友好,各個頻道頁接入漸進式首屏後用戶能更快的查看到內容數據。但在圈子開發的過程中,我們發現對於個性化推薦的場景之前提出的漸進式首屏方案無法較好的支持。爲此我們選擇了降級方案,調整了從圈子廣場頁到圈子主頁及相關子頁面的路由跳轉邏輯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/cd\/cd36c736e05c9e03a6f64ed3b050465b.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖,通過制定上下游頁面之間的數據緩存約定來達成容災和提高交互體驗是目的。在每次頁面路由跳轉時都將相應的業務數據進行緩存,在下一級頁面對消費相應的緩存數據。這樣不僅可以在網絡環境較差的情況下提升用戶的體驗。同時在接口報錯時進行可以起到最低程度的有效兜底,避免用戶體感過差。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/73\/73fa13187e8340818b8be35c3a83bad8.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在此基礎上爲了提升頁面首屏的渲染速度,我們接入提升"},{"type":"text","marks":[{"type":"strong"}],"text":"數據預取方案"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"strong"}],"text":"離線包緩存"},{"type":"text","text":"方案。將首屏頁面渲染過程中最爲耗時的"},{"type":"text","marks":[{"type":"strong"}],"text":"資源包加載過程"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"strong"}],"text":"首屏接口請求過程"},{"type":"text","text":"做了並行化處理,從而降低了首屏展示的等待時長。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/65\/65c039aa80ca02abd6d59c2f5219feda.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優化前後效果對比:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/26\/262e0e6dd52589c166adf1be32dd0e39.gif","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"優化前"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/10\/1062742baa32793c4e26268e937f0696.gif","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"優化後"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"後續展望"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會玩圈子的首個版本在遭遇各種小問題後終於順利上線了。在這個過程中解決了部分在之前電商導購場景下未經歷過的問題:例如角色權限管控,多狀態值管理等問題。這些經驗的沉澱對於之後閒魚社區內複雜C端應用體系的成長可以提供一定的助力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但目前仍有許多的問題點待我們思考優化:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前圈子主頁的首屏平均可交互時長爲1000ms左右,用戶從點擊入口到進入主頁內瀏覽基本無需等待。但我們相信通過根據設備類型來做區分,在進入頁面之初降級部分中低端機非必須能力能夠爲這一類用戶提供更快的交互體驗。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了突出社區內不同圈子個性點,相信自定義的裝修能力以及定製插件能力在之後是必不可少的。要如何能夠基於現有的架構體系快速接入這些業務訴求,也是我們在現有能力上需要預先思考到的"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根據業務訴求的變化,如何將從業務模塊中產生的組件儘量做到更通用化並且支持多種容器也是需要解決的。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文轉載自:閒魚技術(ID:XYtech_Alibaba)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"},{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s\/OwM2eThu0_XviANXiJQNrg","title":"xxx","type":null},"content":[{"type":"text","text":"0到1:閒魚高複雜度高性能社區圈子開發實錄"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章