導語
2021 年 618 已經圓滿下線,平臺下單金額創新高,達到了 3056 億。作爲大促線的主要前端承接團隊,今年負責了 16 個會場的開發。本文將從會場創新功能、技術框架以及協作方式這三方面來揭祕,如何在短時間內開發完 2021 年多會場、高要求的 618 大促,化解禿頭危機。
不一樣的 618
1. Taro3 應用:拉通 H5 和小程序
近幾年小程序由於在用戶觸達、用戶留存方面的優勢越來越受重視,團隊也接觸過需要在小程序中開發的會場(非 H5 形式),而 Taro 的優勢正是用同一套代碼打包出多端運行的程序,這符合我們對小程序開發的需求。考慮到日後的業務渠道,我們在 2021 年 Q1 完成了 Taro3 技術棧在會場的落地。在這個過程中,我們遇到了 2 個白屏問題:安卓低版本瀏覽器白屏以及主購小程序白屏。
- 安卓低版本瀏覽器白屏
產生這個現象,一般是由於低版本瀏覽器對高階語法的兼容性不夠導致的,在將頁面不斷簡化後發現普通一個空白項目也會白屏。最終將問題確定在 Web Components 的使用上。由於目前會場主要渠道爲 H5 形式,在和 Taro 開發團隊反饋討論後,針對 H5 的應用,把 Web Components 實現的基礎組件,替換爲 React 組件;在小程序中不做修改。Dom 節點如下圖所示:
目前最新版本 Taro 已經同步該功能,使用者不需要特殊處理。一套項目代碼,解決 H5 頁面開發和小程序開發,節省一倍開發量。
- 京東購物小程序對H5鏈接hash路由的特殊處理導致白屏
Taro3 打包 H5 時會添加默認 hash 路由,在通天塔(活動發佈平臺)發佈活動時無法使用 history 路由,同時京東購物小程序和京喜小程序在 WebView 處理鏈接時會添加一些參數以及 hash 參數,從而導致小程序中 H5 頁面路徑錯亂。解決方案有三個:
- 和小程序提需開白名單
- 修改H5的鏈接地址增加“omitH5Params”
- 更改Taro3路由設置
由於大促會場個數多達 16 個,採用方案 1 和方案 2 需要統計各個會場以及渠道的鏈接,風險很大。因此和 Taro 開發團隊討論,最終實現了方案 3 的效果,新增路由配置鉤子,針對 H5 進行單獨的路由設置,通過通天塔默認的鏈接即可在小程序中訪問會場。減少了開發和運營維護成本。
最終項目關鍵配置如下:
router: {
forcePath : '/',
customRoutes: {
[`/pages/${process.env.TASK_DIR_NAME}/index`]: '/'
}
}
2. 容災服務:用戶體驗的保障
大促會場在線時長 1 個月左右,訪問 PV 上億,對頁面安全性要求非常高。對於數據異常情況,前端處理的方式有兩種:
- 請求異常時跳轉簡單版通天塔頁面
- 監控請求,異常時採用內置數據兜底
從用戶體驗上考慮,兩個方案各有優缺點。方案一優點在於能展示實時的商品、廣告組信息,缺點爲頁面結構和預期不同,缺少交互引導;方案二優點在於和正常時頁面結構一致,缺點在於數據爲固化,不能及時跟進運營策略調整。爲此我們對容災進行了整體流程設計:
今年我們採用了兼顧方案一、二的新版容災服務,由客戶端(各會場)各自配置監控的接口(通常是首屏數據拉取接口),以及備份數據的間隔時間(通用爲 1 小時),由服務器來進行去個性化數據的請求備份至 OSS 服務器,從而實現以下效果:
- 不存在頁面跳轉,保證用戶體驗符合預期;
- 跟隨運營策略動態更新,兜底數據間隔 1 小時(可配置)備份一次。
在 618 專場期、高潮期,我們統計了容災服務的曝光,如下圖所示(數據敏感性暫不提供具體值):
3. 智能 UI:有效提升轉化率
隨着精細化運營策略的深入,以及智能化應用的普及度,會場中商品 BI 已經不能滿足用戶訴求。今年加入了“智能 UI”的概念。根據構建用戶設計畫像,同樣的商品信息/會場入口,通過前端呈現不同設計風格的樣式。如上圖所示。
針對前端來說,需求可以簡化爲:頁面加載時,通過請求後端接口下發的用戶設計畫像,決定商品/店鋪的 UI 樣式。
-
功能實現
作爲典型的 SPA 項目,頁面會在加載完 index.html 和主腳本後纔會開始請求頁面數據並由 js 渲染出來,如下圖所示:
爲了防止頁面二次渲染,我們可以在請求頁面數據的同時並行請求智能 UI 接口,如下圖所示:
-
實現效果
以主會場底部 feeds 以及店鋪入口爲例,實際頁面效果如下:
從交互同學對活動覆盤的數據來看,智能 UI 策略對樓層的點擊率、轉化率都得到了有效驗證。
4. 下拉刷新:頁面刷新的另一種方式
在京東購物 app 首頁,通過下拉操作可以觸發頁面刷新,甚至在於某些特殊日子(比如 618 大促),下拉可以觸發 xView 來投放會場入口,由此可見用戶已經被培養出下拉操作的習慣。但是在會場中,如果需要更新頁面數據(比如秒殺商品),只能返回上級頁面重新打開。
由於大促會場是通過 WebView 來呈現的,在和負責團隊溝通後,2021 年 618 第一次在會場中上線了“下拉刷新”功能。
-
功能實現
首先我們需要通過導航欄統一配置協議設置 WebView 支持下拉刷新,同時設置在下拉刷新開始時調用的函數名,最後我們只需要在回調函數中寫下我們頁面刷新邏輯即可。
-
實現效果
5. VR 轉盤:酷炫的 Z 世代
對於崇尚個性,拒絕跟風,對於新鮮事物都有較強的獵奇以及嘗試心態的 Z 世代人羣,大牌制燥廠從運營策略、設計風格到動效呈現上都做出了相應的調整。VR 轉盤就是一個典型案例。
我們先來看一張視覺設計時的對照圖,可以看到大家對於實現精準性的要求是相當高的:
- 功能實現
輪盤的處理主要考慮到三部分:初始化、轉動過程中、停止轉動。
- 初始化:處理圓形繪圖(每個卡片高度設置、居中,以及旋轉角度),設置各狀態初始值,包括圓心座標、觸摸起點座標、轉動前角度、轉動狀態、鎖等。
- 轉動中:
- 觸摸時:記錄當前輪盤角度以及開始座標、釋放鎖
- 滑動過程時:判斷是否橫向滑動,設置狀態,計算滑動角度以及當前item索引,輪盤動畫處理。
- 停止轉動時:判斷當前操作是否足以轉動(以1/2個卡片角度爲標準),釋放鎖,設置轉動狀態,觸發輪盤迴調。
- 實現效果
小結
2021 年 618 中還有很多新穎的交互形式(比如全渠道的 AB 頁、Z 世代的詞條選擇等等)、和往年大促相比取得更高點擊、轉化率的模塊(比如:百億購物金系列、事業部樓層優化等)。可以參考設計同學整理的戰報。
精彩交互展示:
開發揭祕
1. 技術框架
從加入京東來以來,經歷了最初的 gulp + ejs、再到後來的 Webpack + Vue/React、 現在的 Taro3,我們迭代的最終的目標有以下 4 個:
- 更極致的性能
- 更快的開發效率
- 更低的維護成本
- 穩定的複用和迭代
首先通過底層基礎配置和 EUI 組件庫的支持,接着在中間層封裝常用的工具庫,配合不同業務模塊之間的組合,最終完成會場的開發工作;而這一系列分工、組合的基礎,離不開良好的團隊規範的實施;在完成本職的前端工作之外,團隊也會思考將來的技術方向(智能化)以及更好的用戶體驗(容災)。具體如下圖所示:
2. 高效的協作方式
開發週期短且工作量大的項目必然會遇到團隊協作的場景,目前我們經常處理 3 類情況:
- 多人協作同一頁面,比如大牌制燥廠和場景頁
- 多人協作同會場不同時期頁面,比如主會場4個時期
- 同一組件在不同會場中的複用,比如百億購物金在大促會場的貫通
因此,高效的協作方式、合理的分支組織、科學的版本迭代變得尤爲重要。
- 代碼分支規範
開發項目時基於產品需求來做代碼分支管理,原則上一個分支對應一個需求。項目在開發週期存在一個開發分支dev
,所有的功能分支都基於開發分支dev
來創建,並以feature-xxx
的形式來命名 。
當功能模塊開發完成後,再將該功能分支合併到開發分支dev
如果分支dev
在合併了某個功能分支之後出現了問題,我們也可以很快的回退到合併分之前的節點,甚至檢出問題分支,從而確保開發分支的可靠性
和易維護性
- 公共模塊維護
公共模塊的管理一直是開發中需要重點思考的問題。公共模塊可以分爲以下兩類:
- 技術層面的公共模塊
對於技術層面的公共模塊,如請求庫
、組件庫
、工具類
等,可以集成在腳手架裏,項目初始化的時候通過npm
的形式來引入。對於同一項目不同分期的公共代碼,
比如預加載模塊
、容錯組件
、底部導航
等,通常來說可以建一個文件夾,比如common
,用於存放。
- 業務層面的公共模塊
對於業務層面的公共模塊,可能會隨着開發週期而累積,因此無法像工具類
等模塊提前集成在腳手架裏。比如今年的 618 活動,很多會場都包含了紅包雨
、倒計時
等功能,這些功能在不同會場之間的表現是大同小異的,因此可以共用同一套代碼即可。
在不同項目中引入公共代碼,一般有npm
、git submodule
、git subtree
等方式。它們各有優缺點,比如npm
更側重於包的依賴管理,但是無法做到雙向同步,這就意味着需要有專人去維護這個包,假如我在當前的項目中開發了一個組件,這個組件在別的項目中也可能需要用到,但是我卻無法將其提升到npm
包裏邊,而需要相應的人去做這個事情。又比如git submodule
,它的特點是允許在一個項目倉庫中嵌入另一個子倉庫,但是所嵌入的子倉庫是基於某個commitID
,如果其他開發者在操作子倉庫時沒有按照相應的規範,導致原本的commitID
發生變化,則有可能對所有引入了該子倉庫的項目造成影響。
公共模塊管理方式對比
方式 | 優點 | 缺點 |
---|---|---|
npm | 方便引入,可在多項目中使用 | 無法雙向同步,需要專人維護、專人發包 |
git submodule | 以子倉庫引入,目錄清晰 | 基於 commitID,commitID 發生變化可能導致子倉庫變化 |
git subtree | 以子倉庫引入,目錄清晰 | 子倉庫的更新與推送指令相對複雜 |
git subtree
相對來說更符合我們的需求,它像git submodule
一樣允許我們在當前項目中引入子項目,這個子項目就像其他的普通目錄一樣直觀,如果發生新增公共模塊或修改功能模塊等變更,只需要像維護其他倉庫一樣去維護子項目對應的倉庫,再回到當前項目中去同步子項目代碼即可。
- 項目版本迭代
由於 618 的活動持續時間較長,同一個活動項目可能會分爲預熱期
、專場期
、高潮期
等不同分期,每個分期都有相應的變化,比如新增樓層、新增功能等。如果把預熱期
的功能發到了高潮期
,或則把高潮期
的配置弄成了專場期
,則可能導致災難性的問題。
一般來說可以通過分支來管理不同分期的代碼,但這要求開發者要有較強的分支管理能力,並及時同步代碼更新。即便如此,如果發佈項目時切錯了分支,仍會造成嚴重的事故。
爲了避免上述情況,我們採取了以下措施:
- 不同分期對應不同入口文件
- 不同分期特有功能/樓層存放在分期命名目錄下
- 不同分期配置不同的發佈指令
以京東金榜活動爲例,京東金榜活動在整個 618 活動期間分爲了專場期
和高潮期
,我們在項目中分別用s1
和s2
目錄來對應專場期
和高潮期
的入口:
其中,高潮期
的簽到樓層
和競速樓層
與專場期
不同,因此將這兩個樓層放在s2
文件目錄下:
然後通過配置分期對應的活動信息:
通過執行命令yarn deploy -- name=dist stage=1
和yarn deploy -- name=dist stage=2
來區分相應分期的打包部署操作。
使用以上方式可確保每個分期對應指定的入口文件和指定的運行命令,儘可能的避免了迭代出錯的情況。
小結
大促會場的開發,意味着短時間內大量會場(們)的開發上線,同時大促在線時間長,運營策略一定會動態調整,計劃內的工作量之外,還需要考慮變更的人力預留以及成本。因此一個適合快速迭代、高效開發的技術框架,以及高效的協作方式,是支持我們完成任務的基礎。
結語
每一年的 618 活動對我們來說都是巨大的挑戰,高效的開發模式、優雅的協同方式、可靠的容災方案是我們始終追求的目標,我們也會針對每一次活動的變化不斷去精進技術。我們相信只有足夠的技術儲備才能爲京東 618 保駕護航,才能成爲京東 618 業績不斷創新高的基石。
以上是我們研發團隊對 618 活動的開發方式和細節考量,希望能拋磚引玉,共同成長。