當前位置:
首頁 > 最新 > 高品質互動在線課堂:前端開發優化實踐

高品質互動在線課堂:前端開發優化實踐

互聯網教育行業風起雲湧,而高品質在線授課平台是每個互聯網教育公司的核心和基石。本文是tutorabc前端負責人和君在LiveVideoStackCon 2017上的分享整理,主要介紹了在線授課系統Tutormeet+前端開發實踐,包括技術選型、性能優化、持續交付實踐以及APM系統。

演講 / 和君

整理 / LiveVideoStack

大家好,感謝LiveVideoStack提供分享的機會,今天的分享主題是《高品質的互動在線課堂與開發實踐》,是基於我公司的一個授課平台產品展開介紹的。首先,自我介紹下,我有著十多年的前後端開發經驗,最近幾年的重點在前端架構和前端技術體系搭建等工作,曾在途牛等互聯網公司工作,現任TutorABC前端負責人。

今天的主題會圍繞五個方面去講,如何打造一個高品質的在線授課平台?

技術選型方向

優化方向

如何提升課堂的互動性

工程相關的持續交付

前端APM

首先介紹下我們的產品,全稱是TutorMeet+(簡稱TM+),上圖是授課平台的教師端界面,可以看到布局還是比較合理的:有視頻區域、聊天區域、以及教材白板區域,最下面是學生列表。學生端的界面是看上去會更加明亮輕快風格,但總體布局與上圖類似,包括一個雙向白板,輔助的教師控制的功能,這裡只列舉了PC端的效果圖,其他還包括微信端和APP端。

一、技術選型

1)為什麼選擇WebRTC?

我們選擇了WebRTC作為音視頻的技術棧,其實主要是基於以下幾個方向考慮的:因為WebRTC是基於瀏覽器的,無需下載,也無需裝載任何的插件;且開發成本低,官方有詳細的文檔說明,WebRTC的技術社區也相當完善, API常用的也就大概十多個,因此基本上花個半天時間就能熟悉WebRTC是如何開發前端的;以及有Google的出身背景,開源且安全;目前瀏覽器對它的支持也變得越來越友好。最後,Flash將於 2020年徹底退役,這也是轉型到WebRTC的最重要原因。

2)WebRTC瀏覽器佔比

通過上面的WebRTC的瀏覽器佔比圖,可以看到截止到2017年9月,在全球領域內支持WebRTC的瀏覽器已經佔比達到了70%,基本上涵蓋了當代的主流瀏覽器,值得一提的是,8月Safari發布的11版本也進行了支持,這就相當於WebRTC已經將所有「當代瀏覽器」的陣地全部攻陷,而這個比例未來還會越來越高。

3)WebRTC APIs

WebRTC的前端相關API是相當簡單的,主要分了以下三個模塊:

用於處理音視頻方面的MediaStream;

用於建立連接,保持連接,監控連接和斷開連接的RTCPeerConnection;

用於雙向數據通道的RTCDataChannel。

其常用的API非常簡單,這裡做了簡單的羅列,基本上掌握了這些就可以真正開始動手了,其中 chrome://webrtc-internals是Google專門為開發者創造的監控平台,因此在做WebRTC時可能需要一直將其打開,這是比較重要的一條。

4)WebRTC Polyfills&Adapters

瀏覽器在不斷的升級過程中,這些API也會有所變化,因此需要引入Polyfills或者Adapters來對不同瀏覽器和瀏覽器版本之間做兼容和降級處理,這裡主要列舉了三個比較常用的Adapters:第一個是官方出的Adapters;第二個不僅對支持WebRTC的瀏覽器會做出支持,對一些不支持的瀏覽器會通過插件化的方式讓它支持,但由於其並非官方出品,且將來隨著瀏覽器對WebRTC支持程度的提升,建議使用第一個即可。

5)不同場景下的技術選型

上圖是TutorMeet+的教學場景,從業務形態上大概分為兩種形式:

大班課和公開課,即一個老師對很多學生。

小班課,則是1對1到1對3的模式。

對於這兩種業務形態,我們採用不同的技術選型。第一種大班授課方式,採用WebRTC+推流的技術,老師端通過WebRTC跟伺服器端建立一個PeerConnection,伺服器端通過推流到CDN,可以支持一萬個人同時在線觀看直播,這個技術基本上和主流的直播網站技術比較接近,支持RTMP和HLS。小班課使用經典的會議模式,支持智能的服務切換,通過判斷終端的網路環境去動態切換到對應的伺服器。

6)TM+前端架構

上圖是TutorMeet+的前端架構。前端UI層是基於React做的,這部分我們會遵循React的一些最佳實踐,將Component分為四級,第一級是原子化的Component即Widget;還有一個是純UI的Component——可能是由一部分各種原子化Component組成的;最終拼裝成業務Component,或者說容器Component,它對一些業務邏輯進行封裝;我們的狀態管理是用Redux做的,所有數據流的的通信只在Redux和業務Component進行,並不和上面組件庫里的Component通信。最後我們會將對多媒體的操作、對一些WebSocket消息的操作、對一些工具類工具方法以及教師控制方面做封裝。

所有的消息使通過中間件去流轉,這裡我們借鑒了Express中間件的概念,通過一個通信的Bridge去和媒體服務以及消息服務進行通信。前端所有的UI可以通過配置參數動態化載入需要的組件和模塊。值得一提的是,在Facebook最終把React遷到MIT協議上後,我們也將React同時升級到16版本;遊戲開發使用的是Egret引擎。開發構建採用了Webpack3.0,Babel / PostCSS,所有的組建開發是基於React Storybook做的,單元測試使用的是Jasmine,以上就是整個TM+前端整體的架構。

7)在線課堂Web前端的特性

相較體驗一般的Web應用,我們的交互性會更強,用戶在頁面滯留的時間也會比較長——一堂課在45—60分鐘左右,而我們和一般的Web應用不太一樣的地方在於要盡量避免頁面刷新,因為老師端刷新會導致所有的學生出現黑屏的現象。並且由於整個頁面的功能非常豐富,包括遊戲、白板、教材、音視頻等等,這也導致了整個靜態的資源包體積非常大,那麼如何去做一個長時間的穩定流暢在線教育課堂?這就需要針對這些特性進行優化。

二、優化

優化會分為三個大版塊去講:

構建時優化,即編譯時優化

運行時優化,

用戶體驗優化

1)構建時優化:

代碼分割

當代的Web前端工程肯定離不開構建, 5年前所有的Web頁面上,可能寫的Source Code就是運行在生產環境上面的代碼,但後來引入了Web前端構建的過程,這部分我們基於Webpack實現。因為我們教室類型比較特殊,分為多種應用場景:公開課、大班課、小班課、課程回放等,這和Client端不太一樣,一般情況下Client端是將所有的業務形態包到一個App或程序中。但Web由於它的靈活性,可以根據不同的教室類型進行拆分,所以第一件事就是將所有的業務類型拆分成多個入口,這裡利用了Webpack的multi-entries特性。

接下來就是對一些大的包進行Code Splitting——做代碼的分割,將一些不需要首屏載入的JS單獨打包到一個bundle裡面,最終它會「按需的」載入到頁面里,不會影響首屏的渲染進程。

第三塊也是優化比較大的一部分,就是對本地的優化語言包進行按需載入,很多第三方庫都有一些語言包的文件,最典型的例子就是moment.js,加上原包可能達到了好幾百K,但其實很多東西是不需要的,因此我們要保證只載入在當前環境下需要的語言包即可。經過上述優化整個包的體積會下降很多,這也是最主要的包的優化手段——對包進行瘦身。

打包優化

利用Webpack3.0的特性:Tree-shaking、Scope Hoisting。Tree-shaking的作用是移除項目中的dead code,之前我們採用uglify.js移除dead code,原理是根據代碼邏輯壓縮、把不需要的模塊和代碼片段從Source Code中移除,Tree-shaking與之不同——是對「需要的模塊進行抽取」,進一步減小包的體積,同時它的配置也更加簡單。以官方例子為例,上圖有三個模塊,其中main.js模塊引用了前兩個模塊,但前兩個模塊在實際中並沒有用到,如果在Webpack2.0或者沒用Tree-shaking的情況下,會將這兩個包同時打進去,這其實是完全沒有必要的,而Tree-shaking則會去除不需要的代碼。

另一個比較重要的優化是Scope Hoisting,熟悉Webpack的同學都知道,Webpack會將所有的模塊都單獨生成一個閉包作用域Function,所有的模塊都整合到一個數組裡,模塊引用的時候通過數組的Index去查找。比如前面官方例子中的三個模塊,最終打包後會生成一個數組,其中包括三個Function,每個Function里是對應相應的代碼,但這樣就會有一個問題:在做模塊引用時,它找會根據數組中index去查找,這是一種低效的方式。而通過Scope Hoisting把所有閉包裡面的模塊全部提到了第一級,最終生成代碼不會再有數組,這樣減少了包的體積,同時又增強了運行效率。

prepack也是比較重要的特性,它是Facebook出的打包優化工具,作用是將在Runtime時的代碼估值儘可能前置到Compile-time進行,這樣就不用再運行時再過多消耗性能,直接在打包時做求值。由此極大的提升了運行性能,同時也減少了包的體積, 從下圖可以看出,從六、七行代碼節省到一行代碼(由於prepack處於試驗階段,暫時還未用到生產環境)。

通過這種前端構建的方式實現了這一點,Source Code和Production Code差距會越來越大,保證Source Code是可讀的、可維護的,而Production Code執行效率是最高的、體積是最小的。以上是構建時優化涉及到的一些知識點。

2)運行時優化

在代碼真正運行到線上時,該如何優化代碼?我們遵循了Google的RAIL模型,在UI層面上的優化很多都是在遵循這種模型的,它主要分為四塊:

響應:100ms內做出響應

動畫:10ms內產生一幀

空間:最大化空閑空間

載入:1000ms內提供內容

響應就是在人機交互時,人在做交互時機器必須在100毫秒內做出響應;動畫也是一樣,保證在客戶端達到每秒60FPS的效果,這就要求在10ms內將幀算出來,再花一定時間將它渲染到頁面上;最大化空閑時間,即盡量讓CPU不運作的時間越長越好,這樣觀看體驗會比較流暢。

載入則是首屏第一次Load頁面時需要在1000毫秒內提供內容。Google做過相關的實驗,首屏載入時間越長,客戶流失就越大,若達到了8-9秒,客戶根本不會在頁面上做任何停留,因此TM+所有的優化都基於這個模型進行的。

這裡不得不提的是像素流水線,也就是一幀是怎麼做出來的。首先進行JavaScript的運算,然後是Style——對當前元素樣式進行計算,接著Layout——元素真正用到頁面裡面會對布局造成什麼影響,最後Paint和Composite分別是瀏覽器內核往頁面上渲染的過程以及對圖層進行合併。

我們可以通過Chrome Devtools調試工具看到這五個步驟之間的時間佔比。大家可以看到,黃色部分為Scripting時間,紫色是Style和Layout時間,綠色是Paint和Composite時間,該例子在Javascript的計算就花了將近16秒,典型的性能不佳。

針對上述情況分析後,接下來就是Profile部分,這部分基本沒有第三方的工具可以選擇,可以說Chrome Devtools是「史上最好的Web開發調試工具」。雖然面板看上去比較複雜,但實際在調試前端性能時通常分為以下幾步:第一選出波峰的一個值,上圖可以看到黃色的地方波峰很高,屬於耗時的波段;接著在底下Timeline將耗時幀選出來,每一幀的耗時大小可以通過寬度來判斷,選中後會在下面展示出該幀消耗的時長;具體分析主要是Bottom-up、Call Tree和Event Log這三項,通過分析它所有的調用堆棧和每一個步驟損耗的時間,定位到需要優化的點再進行優化。

優化一幀的流程大約分為四步,而中間還有兩個比較重要的環節:一是用於分析波段的火焰圖,顯示當前這個波段內所有幀的調用的堆棧,可以直觀的看到哪一幀花費時間長、哪一幀調用堆棧比較深、哪一幀做了一些不必要的操作;第二是內存分析,可以看到內存分析的一個陡然下降是因為瀏覽器做了一次垃圾回收,但瀏覽器頻繁的做垃圾回收也會影響當前執行性能,它的主要的目的就是定位——定位垃圾回收和是否有內存泄露和大對象有沒有釋放的情況,基本上就是這六步。

上圖是針對在線課堂白板的優化實例,當進行一次profile後,我們發現Scripting時間過長,當定位到問題後採用了一些優化手段:首先是頁面上一些JavaScript大的對象進行復用,這就避免了頻繁垃圾回收的過程;其次對所有的白板上的筆記進行路徑上的優化,這樣整個瀏覽器在渲染到頁面上的時間會降低,同時也會使消息通訊時數據量變得更小;節流控制是指對一些連續觸發的頻繁操作進行頻度上的控制,但同時又不能影響用戶體驗;最後就是對白板上的圖形進行拖動、縮放等交互操作的優化。經過上述的優化手段之後,可以發現Scripting時間減少了30%,這是一個比較大的進步。

3)用戶體驗優化

接下來從用戶體驗的角度,該如何優化我們的在線課堂?其實和一般Web開發的經驗差不多,舉例來說:

預載入/懶載入:對頁面上的教材、視頻進行預載入,以及對非首屏圖片教材進行懶載入。

響應式布局:根據不同解析度的屏幕,使他的看上去的視頻大小和白板教材的大小,正好是最適合的。

漸進式用戶體驗:讓用戶在不同的設備上都能有所體驗。在一些不支持,比如低端的機器上進行降級處理,也能使用在線課堂。

層級管理在我們應用中顯得特別重要。因為頁面特別複雜,導致上面有很多層,包括布局層、上面有內容層、白板層、遊戲層、控制層等等,因為層級較多,需要對頁面z-index進行管理:對每一層進行一個z-index區段的限定,如第一層限定在0到10。

Web安全色/安全字體:要保證在不同的終端上看到的東西是一樣的。比如在蘋果的電腦上用蘋果的字體,但在Windows設備上顯示不對,不同的字體寬度也不一樣,出現換行的問題,尤其是在白板上寫字時,可能會有對不齊的情況,極大的影響用戶體驗。

三、互動性

除了對在線課堂的優化,我們在授課過程的互動性上也做了產品的優化、升級,這是因為K12教學對整個授課內容的趣味性有很高要求,單純的基於音視頻白板教材的在線課堂已經無法滿足用戶的需求。這裡簡單列舉幾個Feature。

1)遊戲化白板

首先引入了遊戲化白板的概念,這主要用於青少兒教學的場景,即老師可以通過播放一段遊戲讓學生去玩,從而提升整個在線課堂的互動性。除了老師和學生之間的互動外,學生之間可以通過遊戲進行競賽,同時配備一定的激勵機制。這部分是Egret引擎實現的。

2)屏幕分享

屏幕分享用於某些場景下的教學,比如Photoshop軟體的教學,需要將操作的頁面分享給學生。它的實現是基於Chrome本身的支持,不過必須通過插件的方式去調用,整個屏幕視頻流推送是通過WebRTC實現的。

3)回顧課

第三個是錄影檔結構化,它和視頻網站的進度條索引很像,我們針對上課不同的節點來進行分段,每一段都會對應一個縮略圖,讓學生可以看到它的具體內容,這樣學生就可以快速的定位到所需的章節,同時也能大大減少伺服器端的流量。

四、持續交付

1)持續交付的目的

對於項目上線後迭代的過程中不出錯且穩定運行而言,持續交付很重要。它是為了適應快速迭代的需求,盡量做到自動化,降低人工成本,保證從開發到上線流程中的所有人員可以更緊密的合作,同時也要保證生產環境的上線質量。針對整個前端的持續交付要達成以下幾個目的:

要保證源碼清晰的分支管理,和比較清晰的發布策略;

要保證所有核心模塊的高覆蓋率測試;

所有的靜態資源都是通過非覆蓋,增量式的發布到CDN Server;

線上出問題時進行快速回滾。

2)持續交付架構圖

上圖是持續交付的架構圖,所有的第三方模塊都通過npm去託管,源碼管理使用GitLab,整個CI Server採用Jenkins,Jenkins在發布時會做一些代碼風格的檢查,Unit Test、Benchmark和端對端測試,通過這些測試後發布到測試環境,通過後再發到生產環境。這樣整個發布到測試的過程只需要花費幾十秒鐘的時間,測試完成到上線的過程會壓縮到一個小時,並且也極大的提升了上線的質量。值得一提的是,我們通過Webpack的Define-Plugin 和Multi-entries 實現了差異化按需打包。也就是說整個項目,所有的代碼庫是一個,但真正生產出來的代碼是N份。

3)持續交付技術點

這部分涉及到的技術點主要包括以下幾部分:第一是私有的包管理庫可以使用Git倉庫,或者源碼倉庫去代替;第二是前端構建的三劍客——Webpack、Node.js和npm script;可能免不了寫Shell Script,但這裡有個最佳實踐就是:前端盡量用前端的技術去解決整個發布過程中的技術點,因此盡量使用node.js+npm script代替Shell Script;第四個是Jenkins、Git-webhook,有一些過程是直接通過Web自動觸發的;最後是代碼風格檢查和測試的一些框架,比如eslint、stylelint、jest、benchmark、Nightwatch等等。

五、前端APM

前面這些解決了整個項目上線發布的過程,但真正線上運行時會很多問題出現,需要監控整個上線的運行質量。因此就需要做一套前端APM系統,它主要達成以下幾個目的:

性能監控:包括首屏載入的指數(比如首屏直接相應速度),內容下載的速度,並且對整個交互過程中可預期的一些耗時操作進行埋點,上報操作所消耗的時間。

錯誤採集:我們對所有未捕獲的異常進行了全量採集,對整個頁面上所有靜態資源、載入失敗的異常也進行了採集。針對這種捕獲的異常,進行按需採集。

業務數據上報展示:為了保證音視頻的質量,我們會周期的上報客戶端的丟包率,網路延遲等等相關的實時數據。同時也會對當前客戶端的類型,包括如瀏覽器類型、用戶IP等進行上報,以及用戶的行為和關鍵流量節點。

後端是採用ELK做的,因為Kibana有強大的數據可視化分析功能,可以節省很多工作量,它可以動態的顯示當前的客戶端的佔比,IP地域分布等情況。

前端APM埋點,我們遵循以下幾個最佳實踐:

對上報數據進行分類、分級,方便後期做報表和ELK中的統計分析。

盡量做到無痕埋點,比如說全量採集完全可以通過無痕埋點做到。

聲明式埋點替代命令式埋點,也就是盡量減少埋點代碼對異構代碼的侵入性。

對業務方面的數據要做到按需採集,減少分析時的噪音,使最終採集數據更加準確。

下圖是TM+項目所用到的技術棧,全部都是開源的。

六、總結

接下來我們可能會在以下幾個方面進行嘗試:

首先是引入人工智慧,人工智慧在在線教育的場景下是非常適合,包括現在比較成熟的人臉識別、語音識別和機器翻譯。

引入AR/VR概念,給學生帶來沉浸式的教學體驗。

多終端統一,也就是希望將所有終端的開發都收納到Web 這個技術棧,會引入React Native / Hybrid App/ Electron這些框架。

WebAssembly,可以使頁面具備運行二進位碼的功能,讓瀏覽器端計算端性能大步提升,而在音視頻領域有很多計算密集型的場景,我相信WebAssembly在接下來一段時間會在這個方面發揮很大的功效。

今天的分享到此為止,謝謝大家。

WebRTCon 2018 7折火熱報名


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 LiveVideoStack 的精彩文章:

展望2018:WebRTC和下一代編解碼器

TAG:LiveVideoStack |