貓耳大型活動提效——組件低代碼化

1. 引言

貓耳前端在開發活動的過程中,經歷過傳統的 pro code 階段,即活動頁面完全由前端開發編碼實現,直到 2020 年接入公司內部的低代碼活動平臺,滿足了大部分日常活動的需求,運營可自主配置活動并上線,釋放了相當一部分的開發人力。不過,此時的方案仍然無法很好地服務大型直播活動場景,比如年度 S 級的直播活動,這類活動賽程多且持續時間長(可長達兩周),頁面和組件都包含多種狀態,運營難以配置出大型直播活動的所有需求,故此階段的大型活動仍然完全由開發編碼實現,需要占用較多人力,但此類活動從數量上來看連 1% 都不到。鑒于我們已在日常活動中積累維護了相當多功能的低代碼組件,如何復用已有的低代碼組件來更快實現更多活動玩法就成了一個值得研究的問題。此外,大型活動從籌備到結束,時間長達數月,而密集開發階段可能只占其中的一個月,密集開發結束后的長尾需求又該如何優化提效?接下來本文將介紹貓耳前端在活動場景的低代碼探索經驗,以及最終穩定的開發模式。

2. 場景分析與問題識別

2.1 不同場景的開發方案

把時間先撥回 2022 年,當時我們已有一定的平臺使用經驗,從技術角度將活動劃分為兩大類型,根據業務需求采取不同的方案:

2.1.1 配置類頁面(Low Code + No Code)

此類活動經產運及技術負責人評估后,若無需開發參與則由產運同事自助配置并上線。若需要開發參與,則視情況修改組件或開發 JS 或 CSS 補丁代碼來實現,沉淀下來的代碼也可用于后續的類似活動。

圖片

2.1.2 開發類頁面(Pro Code)

圖片

在一些玩法較為復雜、活動狀態多的場景,配置頁面的難度可能會呈指數級上升,當時平臺也并不具備完善的預覽能力,所以此類活動幾乎完全由開發負責實現(部分頁面可能會跳轉到配置類頁面)。雖然工作量較大,但簡單來說就是根據設計稿、產品需求文檔、接口文檔這幾個關鍵輸入來實現活動頁面,在流程上并沒有太多可說的。

圖片

2.2 問題與嘗試

回到引言的問題,在討論更具體的解決方案之前,我們先看看在經過幾次大型活動的 pro code 開發后發現了哪些問題,在前期又做了哪些嘗試:

2.2.1 活動規則變更效率低

由于活動頁為了保證用戶體驗會集成較多的玩法規則,由于運營無法在活動的密集開發階段一次性給到準確無誤或完全不變的規則說明,在活動上線前,前端需要持續配合更新頁面內的活動規則,有時候是換圖,有時候是調整文字描述,改動的發布流程較長且影響開發測試效率。

前期嘗試:比較泛的解決方法是將前端寫死的切圖改為從靜態資源服務中獲取,我們也確實在個別活動中嘗試約定過資源路徑,產運將資源上傳到特定路徑后,開發使用約定好的路徑來加載資源,但此方案并沒有很好地利用現有的低代碼平臺(如:配置間距、管理資源版本),也存在額外的上手成本和維護成本。

2.2.2 部分常見的需求處理效率低

相似需求總是需要走開發上線的流程,導致開發人力總是緊張,且效率難提高,如:

  • 每次活動都會設計新的榜單樣式,這類換皮工作對開發來說耗時且枯燥,影響其他需求的開發進度

  • 直播活動結束后,開發需要按業務流程固化榜單數據,每次都需要將服務端導出的數據替換到代碼中,然后再走一遍上線流程

該問題在前期并沒有想到很好的處理方法,直到后續復用低代碼組件才得以解決。

2.2.3 重復開發組件

前端在大型活動中存在重復開發組件的情況(如:直播榜單組件)。榜單在直播活動中是標配組件,但大型活動頁面狀態較為復雜,無法直接通過低代碼平臺配置,導致這類場景我們一直沒能復用運營配置的組件,于是又額外開發維護了一套 pro code 場景的榜單組件。

前期嘗試:將配置了單個 low code 組件的頁面通過 iframe 的形式載入頁面框架內,也確實滿足了一些活動需求,但同時也發現了其局限性:

  • 組件若涉及彈窗和遮罩,由于彈窗和遮罩都是基于 iframe 頁面插入的,難以直接基于宿主頁面居中擺放彈窗,遮罩的處理也比較復雜

  • 頁面之間可能存在跨域的情況,個別需求得花心思解決

  • iframe 頁面完整加載較慢,會重復請求宿主頁面加載過的資源,部分請求也并非必要

以上提到的幾個痛點,不僅影響我們每次活動的交付效率,也使得前端團隊整體的資源利用率較低,前端團隊總是處理類似需求得不到成長,也無法推進其它業務需求。

3. 解決方案與實施

秉持著不寫新代碼就沒有新 bugDRY 的開發原則,作者在經過幾次 pro code 活動后開始思考:是否有方案可以解決以上問題,讓我們可以有精力去做其它更加價值的工作?

3.1 遠程組件

2022 年 10 月,首個接入B站遠程組件能力(內部名:片段加載器)的貓耳直播活動上線,本次活動在 pro code 頁面框架的基礎上加載了運營配置的低代碼榜單組件、彈窗、活動規則等內容,解決了第一部分提及的所有問題。

圖片

3.1.1 原理

顧名思義,遠程組件依賴于服務端的組件數據,其包含三大數據:組件 JS 資源、組件 CSS 資源、組件 JSON 參數(運營配置)。組件數據的拉取、組件的渲染等工作,則由客戶端的加載器提供支持。

前端研發人員在 pro code 頁面框架內集成加載器后,只需傳入約定好的頁面片段 ID,加載器即可完成頁面片段的拉取工作,并復用 low code 頁面的渲染器完成渲染工作。

圖片

3.1.2 項目工作流

上述編碼細節轉變的背后,更深層次的轉變其實是「開發類頁面工作流程」的轉變,以及項目人員的工作職責變化。

圖片

從新的流程中不難觀察到,前端能夠在設計稿尚未交付的情況下就提前介入,設計一些適合低代碼化的功能模塊,然后轉交給運營配置使用。前端不僅能夠在更專注業務邏輯的情況下提前交付運營也在復雜活動中獲得了調整和發布的能力(僅限于部分功能模塊),一些運營側的調整也不必再走前端的發布流程,減少各端溝通返工的情況,項目的整體效率更高。

回到第一部分的具體問題來說,技術側從以往活動中識別出后期需求、維護需求、效率問題后,可以借助低代碼平臺將流程功能化,從而實現更順滑的交付效果。

3.1.3 接入前后的代碼對比

舊的代碼實現

為了更好地理解效率提升的效果,讓我們先看一個典型的舊代碼實現示例。這段代碼展示了如何編寫一個直播榜單組件,一個需要定制的 pro code 榜單通常需要 100+ 行的 CSS 代碼,這也意味著前端要等設計資源完全 ready 后才能進開發(給設計也帶來了壓力),而在活動中需要定制的榜單往往不止一個,且每次活動都需要開發。在活動 DDL 明確的情況下,很容易給前端造成任務堆積,人力不足的問題。

圖片

新的代碼實現

現在,通過采用遠程加載低代碼組件的方法,我們大大簡化了這個過程。下面是一個使用遠程加載低代碼組件的示例代碼。前端只需一行代碼即可加載運營配置的 low code 榜單組件,無需編寫繁瑣的 CSS 代碼,設計同事也可以調低榜單模塊的優先級,優先完成其它高優的設計任務。

圖片

以下是直播榜單組件在后臺系統中的界面截圖,展示了運營人員如何通過界面配置而不是編寫代碼來完成同樣的任務。

圖片

3.2 接入方案

以下是貓耳前端在接入公司內部低代碼平臺過程中積累的接入方案。

3.2.1 Pro Code 頁面能力對齊 Low Code 頁面

為確保 low code 組件能夠在 pro code 頁面框架內正常運行,我們將一些頁面的基礎能力封裝到了單獨的包內,使得不同環境都能夠獲得一致的效果。

基于 RxJS 實現組件間的數據共享與事件通信

在 low code 頁面中,我們基于 RxJS 的 BehaviorSubject 實現了頁面級別的數據共享方案,各組件可通過訂閱 window 上掛載的 BehaviorSubject 數據流,及時獲取全局數據(如:活動狀態)。

而在 pro code 頁面框架內,在綜合考慮開發成本、性能、隔離性(不考慮沙盒環境)這幾點后,所以我們直接在頁面框架內復用了 low code 頁面的初始化流程,確保各組件能夠直接接入頁面。

圖片

內置 Low Code 環境組件,優化加載速度

在 low code 頁面中,我們用于初始化頁面環境的組件本身也是個 low code 組件,按流程來說,在 pro code 頁面內使用時也需要等待加載器的拉取渲染時間,而其余組件則要等初始化完成后才能正常渲染,所以存在一定的阻塞情況。

圖片

優化前的默認實現

以下是優化前的頁面初始化時序圖。

圖片

優化后的實現

優化后的時序圖已經在遠程組件的 3.1.1 原理小節貼過了,可以返回查看。

簡而言之,我們將 low code 頁面的環境組件直接集成到了 pro code 頁面框架內,跟隨頁面一起構建發布,并且屏蔽了加載器對于環境組件的拉取和渲染邏輯,使得頁面能夠更快完成初始化。

Pro Code 頁面維護所有 Low Code 組件配置數據,支持「合并同類組件的請求」

對于傳統的 pro code 頁面來說,如果出現需要請求同一接口的同類組件(如:多個音頻、多個主播的信息),我們可能只需要在請求時帶上 ID 數組即可,但對于 low code 頁面來說,為了保證最靈活的制作能力,我們不一定會封裝固定布局的組件,更傾向于封裝原子組件或者較為基礎的業務組件,所以運營拖入頁面的可能是一個個獨立的組件(同類組件,但配置了多個),每個組件都單獨配置了 ID,如果不做處理的話可能會并發出非常多的請求。

圖片

圖片

對于這種場景,我們以前采取的方案是:在該 low code 組件的 JS 資源被插入執行時(此時渲染器還沒有渲染組件),讀取頁面內配置的所有同類組件,合并配置后統一發出請求,然后借助 rxjs 緩存接口響應數據。等到組件被渲染器實際渲染出來后,再訂閱該 rxjs 數據源,實現合并批量請求的目的。

如果現在需要在 pro code 頁面框架內實現該場景,對比 low code 頁面我們缺少了直接可用的完整組件配置,需要等所有片段都加載完才能拿到完整組件數據。不過這也不難解決,基于已有的 rxjs 數據共享流程,我們只需要對這類組件稍加改造,將直接獲取所有組件的配置數據改為訂閱所有組件的配置數據。當頁面框架逐個獲取到組件信息后,逐個塞入 rxjs subject 的組件數據列表,然后組件側結合 rxjs debounce 操作符(避免頻繁請求接口),按一樣的流程請求接口獲取數據即可。

以下是簡化后的請求遠程組件并渲染的核心流程。

fetchSegment(pageId) ?.then(async (res: any) => { ? ?if (!res || !containerRef.current) { ? ? ?console.error('segment load failure') ? ? ?return ? ?} ? ?const { info, render } = res ? ?if (!loadedPageIds.includes(pageId)) { ? ? ?loadedPageIds.push(pageId) ? ? ?const newComponentsMap = makeComponentsMap(info.configure?.pageData) ? ? ?window.MissEvanEvents.next((prev: any) => { ? ? ? ?const mergedComponentsMap = Object.entries(newComponentsMap).reduce((acc, [key, value]) => { ? ? ? ? ?acc[key] = (acc[key] ?? []).concat(value) ? ? ? ? ?return acc ? ? ? ?}, prev.componentsMap ?? {}) ? ? ? ?return { ? ? ? ? ?...prev, ? ? ? ? ?componentsMap: mergedComponentsMap, ? ? ? ?} ? ? ?}) ? ?} ? ?render({ container: containerRef.current, needRenderEnvComponent: false }) ?}) ?.catch((e: any) => { ? ?console.error('segment load failure', e) ?})

3.2.2 規范代碼塊開發模式

上文在配置類頁面已經提到過代碼塊,代碼塊由 JS 和 CSS 文件構成,在特定時機插入頁面執行,主要執行一些 dom 操作或添加樣式。在 pro code 頁面框架內集成代碼塊時我們也做了一些優化工作。

由于代碼塊的效果依賴 JS 的插入執行,在按需渲染的場景會存在重復插入執行的情況,若忘記清理副作用也更容易出現問題(如:事件泄漏、定時器無法終止)。為優化該問題,我們在 JS 中臨時加入了一些代碼來檢查邏輯是否執行過,以及定時任務是否需要執行等操作,避免出現不必要的問題,并在后續基于 document.currentScript 設計了一套代碼塊的生命周期函數,用于規范常用代碼塊的參數、執行、清理。

// 代碼塊被插入時的定制邏輯
function mount(dependency) {}// 代碼塊被銷毀時的清理邏輯
function unmount(dependency) {}ContextManager.initLifecycle({ mount, unmount })

???????

我們在 24 年 3 月份將該方案提交給活動中臺并進行了比較密切的幾次討論,平臺綜合各個業務的需求在 24 年 9 月份上線了更加通用的平臺級別的代碼塊開發工具,后續也仍在持續迭代。

4. 成果與效益

4.1 釋放前端開發人力

鑒于活動玩法并非一成不變,不同開發者的能力也有區別,單純的代碼量或是工時人天數據并不能準確體現出低代碼帶來的提升,頂多用于內部預估未來活動的工作量,故以下統計的是各個具有代表性的活動低代碼程度,以及組件和代碼塊的復用情況。由于部分需求比較零散,實際成果可能會比下表更多一些:

圖片

從表中可以發現前端自主開發了非常多的代碼塊,尤其是某些乍一看隨便寫寫也挺快而且沒啥復用價值的功能模塊,我們也選擇將其低代碼化交由運營配置。這樣做的好處是:不僅大部分內容可以實現脫離設計稿提前開發,還可以擺脫許多后期需求和維護需求,對前端開發來說是一個非常有利的提效模式。

從崗位職責的角度來看,也可以認為代碼塊開發模式(高頻)是在產品正式介入組件設計前(較低頻),前端提前將功能模塊進行了一部分的抽象設計,便于后續將該功能開發成低代碼組件。在代碼塊開發模式下,運營側的體驗可能弱于組件模式(平臺層面已在優化這個問題,如:降低配置難度,提高開發效率),但是仍能夠保持一定的交付效率,以及用戶側一致的體驗。

4.2 版本管理顆粒度進一步細化

pro code 頁面接入 low code 組件后,也帶來了一個副產品——頁面被打散,版本管理的顆粒度更細了。我們也親身經歷過線上活動出現緊急問題,產運直接調整發布,快速縮小影響范圍然后開發再排查修復的情況。遠程組件讓我們在應急處理線上問題時又多了一種手段。

5. 結語

以上是貓耳前端對于活動低代碼場景的探索和經驗總結,歡迎在評論區繼續討論,一起挖掘業務提效的方法。在此感謝貓耳前端組以及 EVA 平臺組一起參與建設的同事們,特別感謝 EVA 平臺組的璇兒、琥珀草、谷風長道、小白白川、V、Fryderyk 等同事對我們提供的大力支持。對 bilibili 活動中臺系統設計感興趣的小伙伴可以繼續移步查看這篇新活動平臺建設歷程與架構演進。

? ?-End-

? ? ?作者丨Helson、Rui

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/71905.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/71905.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/71905.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度學習系列79:Text2sql調研

參考 https://github.com/topics/text-to-sql 這里是一些資源:https://github.com/eosphoros-ai/Awesome-Text2SQL/blob/main/README.zh.md 這里是綜述文章:https://zhuanlan.zhihu.com/p/647249972 1. 數據集 Spider: 一個跨域的復雜text2sql數據集&a…

Linux 系統負載過高的排查思路

技術探討:Linux系統負載過高的排查思路 在Linux服務器運行過程中,如果系統負載過高,可能會導致性能下降和服務不穩定。以下是針對Linux系統負載過高問題的排查思路和解決方法: 1. 查看系統負載: 使用uptime或top命令查…

【互聯網性能指標】QPS/TPS/PV/UV/IP/GMV/DAU/MAU/RPS

📕我是廖志偉,一名Java開發工程師、《Java項目實戰——深入理解大型互聯網企業通用技術》(基礎篇)、(進階篇)、(架構篇)清華大學出版社簽約作家、Java領域優質創作者、CSDN博客專家、…

linux---天氣爬蟲

代碼概述 這段代碼實現了一個天氣查詢系統,支持實時天氣、未來天氣和歷史天氣查詢。用戶可以通過終端菜單選擇查詢類型,并輸入城市名稱來獲取相應的天氣信息。程序通過 TCP 連接發送 HTTP 請求,并解析返回的 JSON 數據來展示天氣信息。 #in…

Java高頻面試之集合-08

hello啊,各位觀眾姥爺們!!!本baby今天來報道了!哈哈哈哈哈嗝🐶 面試官:詳細說說CopyOnWriteArrayList CopyOnWriteArrayList 詳解 CopyOnWriteArrayList 是 Java 并發包(java.util…

【微信小程序 onTabItemTap:精準監聽 TabBar 點擊事件】

onTabItemTap 是微信小程序中的一個頁面生命周期函數,用于監聽用戶點擊 TabBar 上的某個項時的事件。以下是如何運用 onTabItemTap 的詳細說明: 使用場景 onTabItemTap 適用于需要在用戶點擊 TabBar 切換頁面時執行特定邏輯的場景。例如,你…

痙攣性斜頸需要做手術嗎?

痙攣性斜頸的治療是一個涉及多種醫學知識的話題,讓我們從多方面分析這個問題,來談談是否需要進行手術。 首先,我們要明確痙攣性斜頸是一種什么疾病。痙攣性斜頸是一種頸部肌肉異常收縮的疾病,可能導致頭部持續或間歇性地向一側旋…

AOT是什么?

https://www.bilibili.com/video/BV1Es4y1q7Bf?spm_id_from333.788.player.switch&vd_source12d5954938d20d50645e227a6a728c76&p87常規的java代碼是即時解釋執行的,只有熱點代碼才會提前編譯成二進制,并且將java代碼放到別的電腦執行時得安裝j…

【JavaWeb學習Day23】

Maven高級 分模塊設計與開發 分模塊設計:將一個大項目分成若干個子模塊,方便項目的維護、擴展,也方便模塊間的相互引用,資源共享。 策略: 1.策略一:按照功能模塊拆分,比如:公共組…

圖像的特征

圖像的特征主要包括以下幾類: 1. 顏色特征: 直方圖:描述圖像中顏色的分布。 顏色矩:通過顏色的均值、方差等統計量表示顏色分布。 主色調:圖像中占主導地位的顏色。 2. 紋理特征: 灰度共生矩陣&#xff0…

?LeetCode周賽 3468. 可行數組的數目——暴力與數學?

?LeetCode周賽 3468. 可行數組的數目——暴力與數學? 示例 1: 輸入:original [1,2,3,4], bounds [[1,2],[2,3],[3,4],[4,5]] 輸出:2 解釋: 可能的數組為: [1, 2, 3, 4] [2, 3, 4, 5] 示例 2: 輸入&…

AF3 squeeze_features函數解讀

AlphaFold3 data_transforms 模塊的 squeeze_features 函數的作用去除 蛋白質特征張量中不必要的單維度(singleton dimensions)和重復維度,以使其適配 AlphaFold3 預期的輸入格式。 源代碼: def squeeze_features(protein):&qu…

【打卡d4】日期類--分組輸入

第一題:根據一年中的第 n 天計算日期 📌 知識點 判斷閏年: 閏年條件:能被 400 整除,或 能被 4 整除但不能被 100 整除。平年:2 月 28 天;閏年:2 月 29 天。 累加月份,找…

JAVA(5)-基礎概念

*固定格式 一.注釋和關鍵字 關鍵字:被賦予特定關系的詞 字母全部小寫,如class表示一個類 二.字面量 1.字面量類型 *字符串里面的類型是一句話,用雙引號 字符里面的類型只有一個字或字母 null只能用字符串的方式打印 2.制表符 \t 至少補…

本地部署Navidrome個人云音樂平臺隨時隨地暢聽本地音樂文件

文章目錄 前言1. 安裝Docker2. 創建并啟動Navidrome容器3. 公網遠程訪問本地Navidrome3.1 內網穿透工具安裝3.2 創建遠程連接公網地址3.3 使用固定公網地址遠程訪問 前言 今天我要給大家安利一個超酷的私有化音樂神器——Navidrome!它不僅讓你隨時隨地暢享本地音樂…

C++ 中的RAII(資源獲取及初始化)

C 中的RAII(資源獲取即初始化) RAII(Resource Acquisition Is Initialization)是C中一種重要的編程范式,全稱為“資源獲取即初始化”。它是一種通過對象生命周期管理資源(如內存、文件句柄、網絡連接等)的技術&#x…

藍橋杯嵌入式組第七屆省賽題目解析+STM32G431RBT6實現源碼

文章目錄 1.題目解析1.1 分而治之,藕斷絲連1.2 模塊化思維導圖1.3 模塊解析1.3.1 KEY模塊1.3.2 ADC模塊1.3.3 IIC模塊1.3.4 UART模塊1.3.5 LCD模塊1.3.6 LED模塊1.3.7 TIM模塊 2.源碼3.第七屆題目 前言:STM32G431RBT6實現嵌入式組第七屆題目解析源碼&…

DeepSeek技術名詞全解析:一場屬于中國AI的“覺醒時刻”

在2025年的人工智能浪潮中,一個名為DeepSeek的中國團隊,用一系列技術突破改寫了全球AI競爭的敘事。從“頓悟時刻”到“群體策略優化”,從“冷啟動”到“長鏈思考”,這些晦澀的技術術語背后,是一場關乎人類智能邊界的革…

【Go語言圣經1.1】

目標 學習Go 的編譯方式、包的組織方式以及工具鏈的統一調用方式 概念與定義 package Go 語言通過包來組織代碼。包類似于其它語言的庫librarries或模塊modules,每個包通常對應一個目錄,目錄中的所有 .go 文件都屬于同一個包。特殊的 main 包 : 當代碼…

主流大語言模型中Token的生成過程本質是串行的

主流大語言模型中Token的生成過程本質是串行的 flyfish 1. 串行生成 自回歸模型的核心邏輯: 大模型(如GPT-2)采用自回歸架構,每個Token的生成必須基于已生成的完整歷史序列。例如,生成“今天天氣很好”時&#xff1a…