基于 Flutter 的 Web 渲染引擎「北?!拐介_(kāi)源
阿里巴巴歷時(shí) 3 年自研開(kāi)發(fā)的 Web 渲染引擎 北海(英文名:Kraken)正式開(kāi)源,致力打造易擴(kuò)展,跨平臺(tái),高性能的渲染引擎,并已在優(yōu)酷、大麥、天貓等業(yè)務(wù)場(chǎng)景中使用。
官網(wǎng):https://openkraken.com
Github:https://github.com/openkraken/kraken
背景
互聯(lián)網(wǎng)業(yè)務(wù)如火如荼地發(fā)展離不開(kāi)跨平臺(tái)技術(shù),而最成熟的跨平臺(tái)技術(shù)就是大家熟悉的瀏覽器了,它與生俱來(lái)的跨平臺(tái)能力、開(kāi)放的標(biāo)準(zhǔn)以及強(qiáng)大的生態(tài)使它成為炙手可熱的容器之一。而由于其本身不是為了性能而設(shè)計(jì)的,并且歷史包袱重、兼容性、廠商更新慢等問(wèn)題,瀏覽器在移動(dòng)端的表現(xiàn)并不突出。盡管網(wǎng)絡(luò)以及硬件的發(fā)展帶來(lái)了足夠多的性能紅利,但是日益復(fù)雜的業(yè)務(wù)總能把已有的性能吃透。
過(guò)去也有很多對(duì)跨平臺(tái)方案的探索與實(shí)踐,新的技術(shù)方案也隨著歷史的浪潮不斷地發(fā)展。從最早的 H5 方案到 Hybrid 方案,以及后來(lái)的 Weex/React Native 方案,到現(xiàn)在如火如荼的 Flutter。

熟悉 Flutter 的同學(xué)肯定知道 Flutter 是用 Dart 語(yǔ)言以及 Widget 來(lái)開(kāi)發(fā)的,雖說(shuō) Dart 語(yǔ)言對(duì)熟悉 JavaScript 的前端同學(xué)來(lái)說(shuō)上手成本并不是很高,對(duì)于 Widget 這種基于狀態(tài)驅(qū)動(dòng)的開(kāi)發(fā)模式也已經(jīng)是非常熟悉,但是整體上與已有基建與前端生態(tài)割裂的矛盾是無(wú)法接受的。再者,動(dòng)態(tài)化能力對(duì)于互聯(lián)網(wǎng)業(yè)務(wù)來(lái)說(shuō)簡(jiǎn)直就是剛需,而目前來(lái)看 Flutter for Web 并不理想。
畢竟,引入一項(xiàng)新技術(shù)的第一步是解決引入這項(xiàng)新技術(shù)的成本問(wèn)題。所以我們積極探索一種向上對(duì)接前端生態(tài),向下使用原生渲染的跨平臺(tái)方案。
于是誕生了這款基于 W3C 標(biāo)準(zhǔn)的高性能跨終端渲染引擎——北海(Kraken)。

基于 W3C 標(biāo)準(zhǔn)
Kraken 最終要服務(wù)的用戶(hù)還是前端開(kāi)發(fā)者,那么如何降低前端開(kāi)發(fā)者的學(xué)習(xí)熟悉成本以及如何將老項(xiàng)目快速地遷移到 Kraken 之上呢?我們并不想重新創(chuàng)造一套新的 DSL 作為研發(fā)框架來(lái)給開(kāi)發(fā)者用,如果需要的話(huà),那 Flutter 本身的 Widget + Dart 已經(jīng)做得很不錯(cuò)了。前端開(kāi)發(fā)者可能是用 Rax,也有可能是用 Vue 或是 React 的,我們都期望 Kraken 的用戶(hù)能夠做到“零成本”的快速接入。那么,就需要依賴(lài)一套開(kāi)發(fā)者非常熟悉的標(biāo)準(zhǔn)來(lái)實(shí)現(xiàn) Kraken。

W3C 標(biāo)準(zhǔn)是互聯(lián)網(wǎng)最重要的標(biāo)準(zhǔn)之一,也是前端開(kāi)發(fā)者非常熟悉的標(biāo)準(zhǔn),基于 W3C 標(biāo)準(zhǔn)來(lái)實(shí)現(xiàn)渲染引擎,對(duì)于熟悉瀏覽器的前端開(kāi)發(fā)者可以做到近乎“零成本”的快速上手。同時(shí),我們可以擯棄一些沉重的歷史包袱,使得 Kraken 的渲染效率更高。
強(qiáng)大的前端開(kāi)發(fā)者生態(tài)
受益于基于 W3C 標(biāo)準(zhǔn)來(lái)開(kāi)發(fā),在 Kraken 上前端開(kāi)發(fā)者完全可以使用目前熟悉的龐大的前端生態(tài)。
首先,在研發(fā)框架的選擇上,無(wú)論開(kāi)發(fā)者使用的是 Rax 或者 Vue ,還是 React 或者 Angular 的,都可以保證在 Kraken 上很好地完成渲染。

再次,前端擁有非常繁榮的生態(tài),社區(qū)海量的 NPM 包都可以在 Kraken 項(xiàng)目上直接使用,大量成熟的模塊保證了業(yè)務(wù)開(kāi)發(fā)的效率。

除此之外,開(kāi)發(fā)者平時(shí)在開(kāi)發(fā)項(xiàng)目使用的各式各樣的工具,都可以在 Kraken 項(xiàng)目上直接使用,無(wú)需任何額外的熟悉以及學(xué)習(xí)成本。

通過(guò)對(duì)接了 Chrome DevTools Protocol,使開(kāi)發(fā)者可以直接使用非常熟悉的 Chrome DevTools 來(lái)調(diào)試所開(kāi)發(fā)的頁(yè)面。無(wú)論開(kāi)發(fā)者需要修改 CSS 樣式,還是查看 DOM 結(jié)構(gòu),或者是通過(guò)斷點(diǎn)調(diào)試 JavaScript 代碼,都能保證跟 Web 開(kāi)發(fā)一致的調(diào)試體驗(yàn)。
渲染一致性
Kraken 的渲染能力是對(duì)其 W3C 標(biāo)準(zhǔn)的,所以可以保證跟 Web 渲染的結(jié)果完全一致。
下圖是實(shí)際業(yè)務(wù)的截圖,從左到右分別是 Kraken(iOS),Kraken(Android)以及 Web 版本,可以看出渲染結(jié)果是完全一致的。
比 Web 更好的體驗(yàn)與能力
那么到這里會(huì)有同學(xué)想問(wèn)了,除了與目前前端開(kāi)發(fā)一致的開(kāi)發(fā)及調(diào)試體驗(yàn),以及渲染一致性,那么最終到底能得到怎么樣的能力,以及跟瀏覽器比,到底可以獲得哪些收益呢?
無(wú)限滾動(dòng)列表
在業(yè)務(wù)開(kāi)發(fā)中,有時(shí)開(kāi)發(fā)者會(huì)遇到一些無(wú)法用分頁(yè)卻又大量數(shù)據(jù)的「無(wú)限滾動(dòng)列表」。在客戶(hù)端開(kāi)發(fā)中有 RecyclerView/UITableView 來(lái)實(shí)現(xiàn)滾動(dòng)回收的布局容器,而 Web 標(biāo)準(zhǔn)上盡管也有很多前端側(cè)的優(yōu)化方案來(lái)處理這個(gè)問(wèn)題,但也一直是個(gè)難題。Kraken 嘗試在容器側(cè)解決了此問(wèn)題,增加 CSS Display 屬性值——sliver。
當(dāng) Sliver 容器中的子元素滾動(dòng)出該容器的 Viewport 時(shí),可以將該子元素中用于渲染的 renderobject 回收以達(dá)到節(jié)省內(nèi)存占用的目的。當(dāng)子元素重新出現(xiàn)時(shí),根據(jù) DOM 描述重新生成 renderobject。
這是一個(gè)上萬(wàn)個(gè)節(jié)點(diǎn)的 demo,左邊是 overflow: scroll 的容器,而右邊是 display: sliver 的容器,可以看到 sliver 容器在「無(wú)限滾動(dòng)列表」場(chǎng)景下滾動(dòng)明顯流暢很多。左上角有 FPS 的數(shù)據(jù),可以看到 display: sliver 的容器 FPS 一直維持正常水平,而 overflow: scroll 的容器 FPS 明顯下降。此外,在內(nèi)存方面也有較大收益。
同步光柵化
在瀏覽器中,光柵化是異步進(jìn)行的,進(jìn)行慣性滾動(dòng)時(shí),會(huì)出現(xiàn)白屏,這個(gè)是 WebView 始終無(wú)法避免的問(wèn)題。而借助 Flutter 足夠高效的同步光柵化實(shí)現(xiàn),Kraken 可以做到長(zhǎng)列表快速滾動(dòng)不白屏。
增強(qiáng)的手勢(shì)能力
Kraken 通過(guò)對(duì)常用手勢(shì)進(jìn)行內(nèi)置,使業(yè)務(wù)開(kāi)發(fā)者使用手勢(shì)能力的時(shí)候,再也不需要引入一個(gè) JavaScript lib 以劫持 Touch event 來(lái)做開(kāi)發(fā)了。
以輕掃手勢(shì)“swipe”為例,開(kāi)發(fā)者只需要通過(guò)以下方式就可以獲得一個(gè) element 上默認(rèn)提供的手勢(shì)能力。直接使用內(nèi)置增強(qiáng)的手勢(shì)能力,能夠更快速地開(kāi)發(fā)復(fù)雜的可交互應(yīng)用。
element.addEventLisenter('swipe',(gestureEvent) => {
///...
})
增強(qiáng)的手勢(shì)能力解決了 Web 下原本需要頻繁傳遞事件的性能問(wèn)題以及 JavaScript 處理手勢(shì)占用 UI 線(xiàn)程的問(wèn)題。此外,通過(guò)容器內(nèi)部實(shí)現(xiàn)的競(jìng)爭(zhēng)場(chǎng)能力,可以解決 Web 下手勢(shì)穿透等問(wèn)題。
而內(nèi)置的標(biāo)準(zhǔn)化手勢(shì)能力,也保證同個(gè)容器的不同應(yīng)用下,手勢(shì)交互能力的標(biāo)準(zhǔn)化以及統(tǒng)一性。
插件化能力
除了上面的那些超越 Web 的體驗(yàn)與能力以外,Kraken 非常重要的一個(gè)特性就是插件化能力,插件化能力提供給前端工程師重新定義瀏覽器能力的機(jī)會(huì),開(kāi)發(fā)者只需要編碼一個(gè) Flutter plugin,就可以擴(kuò)展 Kraken 本身的能力。
通過(guò)插件化能力,開(kāi)發(fā)者可以在內(nèi)部實(shí)現(xiàn)許多自定義的標(biāo)簽(譬如說(shuō) Camera 或者自定義的視頻播放器等),也可以基于性能的考慮將常用的業(yè)務(wù)組件(譬如說(shuō) Slider)下沉到容器層。由于瀏覽器廠商開(kāi)發(fā)以及標(biāo)準(zhǔn)制定往往是滯后的,用插件化能力開(kāi)發(fā)者可以快速地自定義各種渲染能力,使業(yè)務(wù)開(kāi)發(fā)可以用到最新的或者增強(qiáng)的各種能力。
除了擴(kuò)展渲染能力,開(kāi)發(fā)者還可以擴(kuò)展手勢(shì)能力,擴(kuò)展手勢(shì)能力可以將以往需要在前端劫持 Touch Event 實(shí)現(xiàn)的能力下沉到容器本身,除了增強(qiáng)了交互體驗(yàn),也給交互提供了更多可能性。
穩(wěn)定性保障
渲染引擎非常復(fù)雜,經(jīng)常出現(xiàn)改一個(gè) Bug 牽一發(fā)而動(dòng)全身,所以需要高覆蓋率的自動(dòng)化測(cè)試來(lái)保障渲染引擎的穩(wěn)定性,每次修改后都需要保障已有的 case 沒(méi)有問(wèn)題。通過(guò)自動(dòng)化測(cè)試來(lái)保障每個(gè) case 與修改之前的結(jié)果做對(duì)比,如果有差異,可以通過(guò) case 以及差異的 diff 來(lái)修改 Bug。
這套自動(dòng)化測(cè)試系統(tǒng)保證了 Kraken 每次修改前后得到的 case 結(jié)果的一致性,以確保渲染引擎本身的穩(wěn)定性。
目前已經(jīng)有近 3000 個(gè)測(cè)試用例,未來(lái)還會(huì)根據(jù)更多的場(chǎng)景繼續(xù)增加,以此來(lái)保證 Kraken 的穩(wěn)定性。

業(yè)務(wù)落地
講了那么多 Kraken 的能力,肯定有同學(xué)想知道 Kraken 在實(shí)際生產(chǎn)場(chǎng)景的表現(xiàn)如何。
目前 Kraken 在 C 端場(chǎng)景移動(dòng)設(shè)備以及低性能 IoT 設(shè)備均有相關(guān)業(yè)務(wù)接入,完全可以使用在實(shí)際生產(chǎn)場(chǎng)景。
在優(yōu)酷 APP 中,Kraken 已經(jīng)落地了大量業(yè)務(wù)。以下方所示身份詳情頁(yè)為例,Kraken 改造后啟動(dòng)有了一個(gè)質(zhì)的提升,相較于同個(gè)頁(yè)面的 原方案,首屏渲染提升28.4%,幀率提升 8.3%。
在 IoT 設(shè)備上,我們的天貓 U 先業(yè)務(wù)在線(xiàn)下低性能的 IoT 設(shè)備上,Kraken 也有非常不錯(cuò)的表現(xiàn)。在線(xiàn)下相對(duì)較復(fù)雜的 Slider 等場(chǎng)景下,動(dòng)畫(huà)以及交互性能都表現(xiàn)較好,長(zhǎng)時(shí)間運(yùn)行應(yīng)用,內(nèi)存穩(wěn)定并無(wú)明顯增長(zhǎng),保證線(xiàn)下 IoT 應(yīng)用的穩(wěn)定性。

社區(qū)協(xié)作機(jī)制
kraken 團(tuán)隊(duì)期望通過(guò)一種良好的社區(qū)協(xié)作機(jī)制,來(lái)與社區(qū)的眾多開(kāi)發(fā)者一起共建 Kraken 底層能力及生態(tài)。
kraken 團(tuán)隊(duì)期望通過(guò)協(xié)作者的方式來(lái)參與 Kraken 功能迭代以及 issue 討論等工作。同時(shí),通過(guò)由一部分協(xié)作者組成的技術(shù)委員會(huì)(TSC)來(lái)確定技術(shù)方向、發(fā)布以及定制標(biāo)準(zhǔn)等工作。
kraken 團(tuán)隊(duì)期望通過(guò)一種公平良好的協(xié)作機(jī)制,讓社區(qū)的開(kāi)發(fā)者能夠更好地參與到對(duì) Web 標(biāo)準(zhǔn)的容器技術(shù)的演進(jìn)中去,讓每個(gè)人的聲音都能被聽(tīng)到,共同促進(jìn) Kraken 以及行業(yè)的發(fā)展。
查看更詳細(xì)的協(xié)作機(jī)制可以移步github。
未來(lái)展望
以往我們?cè)谧銮岸诵阅軆?yōu)化的時(shí)候,往往優(yōu)化到瀏覽器層面就優(yōu)化不動(dòng)了,很難向下進(jìn)行進(jìn)一步的優(yōu)化。而 Kraken 的出現(xiàn),給予了前端工程師新的機(jī)會(huì)與挑戰(zhàn),它提供了前端工程師一個(gè)重新定義瀏覽器的能力的機(jī)會(huì),擁有非常大的想象空間:
超越 Web 的能力,比肩 Native 的性能與體驗(yàn)。 比瀏覽器廠商更快地實(shí)現(xiàn)標(biāo)準(zhǔn),站在標(biāo)準(zhǔn)的前沿定義問(wèn)題,通過(guò)實(shí)現(xiàn)的能力去反推標(biāo)準(zhǔn),促進(jìn)行業(yè)的發(fā)展。 可以自頂向下看整個(gè)渲染鏈路的優(yōu)化及體驗(yàn),通過(guò)全鏈路的手段去優(yōu)化性能以及定義一些新的渲染能力。 目前日益復(fù)雜的前端應(yīng)用導(dǎo)致 JS bundle 的已經(jīng)顯得越來(lái)越臃腫,開(kāi)發(fā)者也可以把常用能力抽象復(fù)用并下沉到容器層面,渲染與公用能力的復(fù)用不再只依賴(lài)于 NPM,可以通過(guò)下沉通用能力來(lái)做更多事情。 通過(guò)“云+端”的結(jié)合,也有機(jī)會(huì)去探索面向未來(lái)的新一代渲染技術(shù)。 基于 Kraken,探索更多的可能性......
最后,期望 Kraken 能給大家?guī)?lái)更好的體驗(yàn)及能力,也希望大家可以積極參與到 Kraken 項(xiàng)目中去,大家一起共建 Kraken 生態(tài)。
官網(wǎng):https://openkraken.com
Github:https://github.com/openkraken/kraken
點(diǎn)擊下方【閱讀全文】訪(fǎng)問(wèn) Kraken Github,給 Kraken star 支持一下吧~
最后
歡迎加我微信,拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...
歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專(zhuān)業(yè)的技術(shù)人...


