整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          React Native應(yīng)用性能瓶頸分析和優(yōu)化

          React Native應(yīng)用性能瓶頸分析和優(yōu)化

          本文結(jié)合React Native跨平臺框架的應(yīng)用工作原理,分析性能瓶頸,分享實(shí)踐中的優(yōu)化性能問題內(nèi)容輸入。

          背景

          隨著移動互聯(lián)網(wǎng)的高速發(fā)展,在很多的業(yè)務(wù)場景下,傳統(tǒng)的純原生開發(fā)已經(jīng)不能滿足日益增長的業(yè)務(wù)需求。為了提升開發(fā)效率,使APP具備動態(tài)化能力,同時提升用戶體驗(yàn),項(xiàng)目中引入了React Native框架。使用過程中發(fā)現(xiàn)部分React Native頁面性能存在一些問題,尤其是復(fù)雜頁面渲染性能較差,于是決定深入調(diào)研和解決這些問題。

          React Native工作原理

          1.概覽

          React Native的頁面使用JavaScript編寫,在JavaScript虛擬機(jī)里運(yùn)行,JavaScript標(biāo)簽/組件最終會被解析為iOS和Android端的View,從而實(shí)現(xiàn)跨平臺。JavaScript代碼運(yùn)行在一個后臺線程,也就是JavaScript虛擬機(jī)運(yùn)行的線程,而不是主線程。這樣設(shè)計(jì)的初衷是為了防止主線程被JavaScript代碼執(zhí)行阻塞,保持UI界面更流暢。JavaScript線程和主線程之間的交互是異步的。

          React Native概覽

          2. 定位問題和優(yōu)化思路

          一個React Native頁面生命周期,一般包括初始化,加載數(shù)據(jù),頁面渲染,事件響應(yīng),頁面刷新,銷毀等幾個過程。接下來將逐一分析這幾個過程中,可能存在的性能瓶頸和優(yōu)化思路。

          2.1 頁面初始化

          頁面初始化時,React Native框架會先從本地文件系統(tǒng)加載JavaScript Bundle文件,并執(zhí)行文件里的JavaScript代碼。

          性能瓶頸:

          ? JavaScript文件加載

          ? JavaScript代碼執(zhí)行

          優(yōu)化思路:

          ? JavaScript Bundle拆包,把公用基礎(chǔ)代碼抽取出來,每次打開頁面,只加載業(yè)務(wù)代碼,減少文件大小,同時也可以減少代碼執(zhí)行量。

          ? 可以考慮使用JS Byte Code,加快JavaScript代碼執(zhí)行速度。

          2.2 加載數(shù)據(jù)

          React Native頁面加載數(shù)據(jù),一般由JavaScript端組裝參數(shù),Native端發(fā)起網(wǎng)絡(luò)請求,再將結(jié)果返回給JavaScript端。

          性能瓶頸:

          ? 一般JavaScript端組裝參數(shù)的時候,可能需要從Native端讀取數(shù)據(jù),會涉及一次或多次JavaScript-Native通信,這個過程是異步的,如果涉及到數(shù)據(jù)傳輸,則會經(jīng)歷JS Object->String->Native Object和Native Object->String->JS Object(JSON序列化和反序列化)兩個過程,比較耗時。

          ? 網(wǎng)絡(luò)請求數(shù)據(jù)

          優(yōu)化思路:

          ? 盡量避免每次加載數(shù)據(jù)時,JavaScript端都要從Native端讀取數(shù)據(jù),最好有一套比

          2.3 頁面渲染

          先看一下React Native頁面渲染過程

          React Native頁面渲染過程

          ?APP啟動,主線程初始化React Native框架。

          ?主線程創(chuàng)建Bridge,加載JavaScript文件。

          ?JavaScript線程解析執(zhí)行JavaScript代碼,生成DOM Tree結(jié)構(gòu)。

          ?Shadow Thread處理樣式信息,生成layout數(shù)據(jù),生成Shadow Tree。

          ?主線程根據(jù)Shadow Tree的層級關(guān)系,和layout數(shù)據(jù),創(chuàng)建Native View。

          ?主線程渲染Native View。

          性能瓶頸:

          React Native頁面渲染,經(jīng)歷了多次線程切換和JavaScript-Native通信,組件渲染也是順序進(jìn)行,雖然是批量操作,但是無法并發(fā)渲染。

          優(yōu)化思路:

          盡量減少頁面的組件數(shù)量和嵌套關(guān)系,復(fù)雜的頁面結(jié)構(gòu),大量的組件嵌套,首次渲染的時候,會非常慢,會出現(xiàn)明顯白屏現(xiàn)象。

          2.4 事件響應(yīng)

          React Native事件響應(yīng)

          ?Native捕捉到Touch,Timer,網(wǎng)絡(luò)等Event。

          ?Native負(fù)責(zé)組裝數(shù)據(jù)。

          ?Native通過Bridge將數(shù)據(jù)序列化為JSON String,傳遞給JavaScript。

          ?JavaScript反序列化JSON為JavaScript Object,處理Event。

          ?JavaScript組裝數(shù)據(jù),序列化JSON String,通過Bridge 回調(diào)Native方法。

          ?Bridge反序列化JSON為Native Object,執(zhí)行Native方法。

          ?刷新UI。

          性能瓶頸:

          在React Native中,Native端負(fù)責(zé)捕捉事件,通知JavaScript端處理,處理完畢之后,再通知Native端刷新UI。一次事件處理,包括了兩次JavaScript-Native通信。

          而JavaScript是單線程執(zhí)行的,如果JavaScript處理邏輯太多,則會出現(xiàn)用戶響應(yīng)不及時。

          優(yōu) 化思路

          在一些事件交互比較多的場景(比如長列表滑動/動畫),盡量把大量計(jì)算邏輯(cell生命周期維護(hù)/動畫每一幀屬性計(jì)算)移到Native端執(zhí)行,減少JavaScript線程的工作量,避免每一幀都要和Native進(jìn)行通信。

          React Native性能優(yōu)化實(shí)踐

          1. 信息中心

          為了減少JavaScript-Native通信的次數(shù),我們設(shè)計(jì)了信息中心模塊。

          JavaScript環(huán)境和Native環(huán)境各自維護(hù)一些狀態(tài)數(shù)據(jù),這些數(shù)據(jù)互不可見,但是雙方都有讀取和同步狀態(tài)數(shù)據(jù)需要,為了減少JavaScript-Native數(shù)據(jù)交互次數(shù),我們開發(fā)出信息中心模塊。

          信息中心的目的是建立一種數(shù)據(jù)同步機(jī)制,減少JavaScript-Native的不必要數(shù)據(jù)交互。

          信息中心

          我們把需要兩端共享的數(shù)據(jù)分為不變數(shù)據(jù),定時更新數(shù)據(jù),實(shí)時更新數(shù)據(jù)三種類型,針對不同的數(shù)據(jù)采用不同的數(shù)據(jù)同步策略。

          ?不變數(shù)據(jù):設(shè)備信息,系統(tǒng)信息,軟件信息等。

          ?定時更新數(shù)據(jù):對精確度要求不高的數(shù)據(jù),比如位置信息。

          ?實(shí)時更新數(shù)據(jù):登錄態(tài),網(wǎng)絡(luò)狀態(tài)等。

          避免每次讀取JavaScript或Native數(shù)據(jù)時,都發(fā)起一次數(shù)據(jù)交互請求,

          開發(fā)者也不必再關(guān)心數(shù)據(jù)同步問題,降低了開發(fā)復(fù)雜度。

          2. Native驅(qū)動的列表頁

          為了解決React Native長列表頁,內(nèi)存占用大,卡頓,容易白屏的問題,我們設(shè)計(jì)Native驅(qū)動列表組件。

          React Native列表頁,用戶交互比較多,列表Cell的生命周期(創(chuàng)建,展示,刷新,移除,銷毀)都是JavaScript端維護(hù),Native端把列表的滾動狀態(tài)實(shí)時傳遞給JavaScript端,JavaScript維護(hù)Cell的生命周期,再通知Native端刷新UI,多次事件交互,導(dǎo)致RN原生列表頁性能差,快速滑動有白屏現(xiàn)象。為了減少,JavaScript線程計(jì)算壓力,減少JavaScript-Native交互,我們推出了Native驅(qū)動列表。

          Native驅(qū)動的列表頁

          Native驅(qū)動列表的優(yōu)勢在于,JavaScript只提供數(shù)據(jù)源和Cell模版,Cell生命周期由Native維護(hù),減少JavaScript線程計(jì)算壓力,渲染更快,沒有JavaScript-Shadow-Main線程切換,減少JavaScript-Native的事件交互次數(shù),支持Cell回收/重用,節(jié)省內(nèi)存,提升速度,流暢度更高,接近Native原生列表,兼容舊系統(tǒng)的JavaScript Cell模版。

          總結(jié)

          React Native應(yīng)用JavaScript線程和主線程,任何一個線程被阻塞,都會導(dǎo)致卡頓和掉幀現(xiàn)象。JavaScript端在處理完事件響應(yīng)或數(shù)據(jù)更新時,需要通知Native端重新渲染UI,這個過程是異步的,因此會略有延遲。在React Native現(xiàn)在的框架下,主要優(yōu)化思路就是減少不必要的組件重繪,減少不必要的JavaScript-Native通信,減少JavaScript線程的計(jì)算壓力,可以把一些原先在JavaScript執(zhí)行的任務(wù),移植到Native端執(zhí)行,實(shí)現(xiàn)由JavaScript驅(qū)動到Native驅(qū)動,都會帶來顯著性能提升。

          參考文獻(xiàn)

          1. https://www.freecodecamp.org/news/how-react-native-constructs-app-layouts-and-how-fabric-is-about-to-change-it-dd4cb510d055/

          2. https://tech.showmax.com/2018/05/react-native-or-not-react-native/

          3. https://reactnative.cn/docs/performance/

          4. https://www.simform.com/react-native-app-performance/

          作者簡介

          禹瀟瀟 58集團(tuán) HRG技術(shù)部

          者:GSYTech

          隨著 RN 團(tuán)隊(duì)關(guān)于 深入了解 React Native 的新架構(gòu) 文章的發(fā)布,這次新架構(gòu)帶來的調(diào)整主要在于以下四點(diǎn):

          • JavaScript Interface(JSI)
          • Fabric
          • Turbo Modules
          • CodeGen

          在 RN App 里,所有的 JS 代碼都會打包成一個 JS Bundle 文件保存在本地運(yùn)行,當(dāng) RN App 運(yùn)行時,一般會有三個線程:

          1. JavaScript 線程:屬于 JS 引擎,用于運(yùn)行 JS Bundle ;
          2. Native/UI 線程:運(yùn)行 Native Modules 和處理 UI 渲染、用戶手勢等操作;
          3. Shadow 線程:在渲染之前計(jì)算元素的布局;

          在 RN 里 JS 線程和 Native 線程之前是通過 bridge 來交互,而交互的數(shù)據(jù)必須被轉(zhuǎn)化為 JSON,而這個橋只能處理異步通信。

          ?

          JavaScriptCore:JavaScript 引擎,React Native 用它執(zhí)行 JS 代碼;

          Yoga:布局引擎,計(jì)算UI位置;

          ?

          一、JavaScript Interface (JSI)

          目前 RN 使用 Bridge Module 來讓 JS 和 Native 線程進(jìn)行通信,每次利用 Bridge 發(fā)送數(shù)據(jù)時,都需要轉(zhuǎn)換為 JSON, 而收到數(shù)據(jù)時也需要進(jìn)行解碼。

          「這就意味著 JavaScript 和 Native 直接是隔離的,也就是 JS 線程不能直接調(diào)用 Native 線程上的方法」

          另一個就是;「通過 Bridge 發(fā)送的消息本質(zhì)上是異步的」,如果需要 JS 代碼和 Naitve 同步執(zhí)行在之前是無法實(shí)現(xiàn)。

          ?

          例如,如果 JS 線程需要訪問 native modules(例如藍(lán)牙),它就需要向 native 線程發(fā)送消息,JS 線程就會通過 Bridge 發(fā)送一個 JSON 消息,然后消息在 native 線程上進(jìn)行解碼,最終將執(zhí)行所需的 native 代碼。

          ?

          而在全新架構(gòu)中,「Bridge 將被一個名為 JavaScript Interface 的模塊所代替,它是一個輕量級的通用層」,用 C++ 編寫,JavaScript Engine 可以使用它直接執(zhí)行或者調(diào)用 native。

          ?

          通用層代表著:JSI 讓 JavaScript 接口將與 Engine 分離,這意味著新架構(gòu)支持 「RN 直接使用其他 JavaScript 引擎,比如 Chakra、v8、Hermes 等等」

          ?

          那 JSI 如何讓 JavaScript 直接調(diào)用到原生方法?

          「在 JSI 里 Native 方法會通過 C++ Host Objects 暴露給 JS, 而 JS 可以持有對這些對象的引用,并且使用這些引用直接調(diào)用對應(yīng)的方法」

          這就類似于 Web 里 JS 代碼可以保存對任何 DOM 元素的引用,并在它上面調(diào)用方法:

          const container=document.createElement(‘div’);

          ?

          舉個例子,在這里的 container 會包含一些在 C++ 中初始化的 DOM 元素的引用,這時候如果我們調(diào)用 container 上的任何方法,它就會調(diào)用 DOM 元素上的方法。

          ?

          JSI 就是以類似的方式運(yùn)行,JSI 將允許 JS 代碼保存對 Native Modules 的引用,并且 JS 可以直接通過引用去調(diào)用 Native 上的方法。

          總結(jié)起來就是:

          • 「JSI 將支持其他 JS 引擎」
          • 「JSI 允許線程之間的同步相互執(zhí)行,不需要 JSON 序列號等耗費(fèi)性能的操作」
          • 「JSI 是用 C++ 編寫,以后如果針對電視、手表等其他系統(tǒng),也可以很方便地移植」

          二、Fabric

          Fabric 是新的渲染系統(tǒng),它將取代當(dāng)前的 UI Manager。

          在 Fabric 之前,當(dāng) App 運(yùn)行時,React 會執(zhí)行你的代碼并在 JS 中創(chuàng)建一個 ReactElementTree,基于這棵樹渲染器會在 C++ 中創(chuàng)建一個 ReactShadowTree

          ?

          UI Manager 會使用 Shadow Tree 來計(jì)算 UI 元素的位置,而一旦 Layout 完成,Shadow Tree 就會被轉(zhuǎn)換為由 Native Elements 組成的 HostViewTree(例如:RN 里的 會變成 Android 中的 ViewGroup 和 iOS 中的 UIView)。

          ?

          而之前線程之間的通信都發(fā)生在 Bridge 上,這就意味著需要在傳輸和數(shù)據(jù)復(fù)制上耗費(fèi)時間。

          ?

          例如如果一個 ReactElementTree 節(jié)點(diǎn)恰好是一個 <Image/>,那么 ReactShadowTree 的節(jié)點(diǎn)也會是一個圖像,但是這些數(shù)據(jù)必須被復(fù)制并分別存儲在兩個節(jié)點(diǎn)中。

          ?

          另外由于 JS 和 UI 線程不同步,因此在某些情況下 App 可能會因?yàn)閬G幀而顯得卡頓(例如滾動有大量數(shù)據(jù)的 FlatList

          「而得益于前面的 JSI, JS 可以直接調(diào)用 Native 方法,其實(shí)就包括了 UI 方法,所以 JS 和 UI 線程可以同步執(zhí)行從而提高列表、跳轉(zhuǎn)、手勢處理等的性能」

          使用新的 Fabric 渲染,用戶交互(如滾動、手勢等)可以優(yōu)先在主線程或 Native 線程中同步執(zhí)行,而 API 請求等其他任務(wù)使用異步執(zhí)行。

          「另外新的 Shadow Tree 將成為 immutable,它會在 JS 和 UI 線程之間共享,以兩端進(jìn)行直接交互」

          ?

          在以前 RN 必須維護(hù)兩個層次結(jié)構(gòu)的 DOM 節(jié)點(diǎn),但因?yàn)楝F(xiàn)在 Shadow Tree 可以共享,在減少內(nèi)存消耗的部分也會得到相應(yīng)的優(yōu)化。

          ?

          三、Turbo Modules

          在之前的架構(gòu)中 JS 使用的所有 Native Modules(例如藍(lán)牙、地理位置、文件存儲等)都必須在應(yīng)用程序打開之前進(jìn)行初始化,這意味著即使用戶不需要某些模塊,但是它仍然必須在啟動時進(jìn)行初始化。

          Turbo Modules 基本上是對這些舊的 Native 模塊的增強(qiáng),正如在前面介紹的那樣,「現(xiàn)在 JS 將能夠持有這些模塊的引用,所以 JS 代碼可以僅在需要時才加載對應(yīng)模塊,這樣可以將顯著縮短 RN 應(yīng)用的啟動時間」

          四、Codegen

          「Codegen 主要是用于保證 JS 代碼和 C++ 的 JSI 可以正常通信的靜態(tài)類型檢查器」,通過使用類型化的 JS 作為參考來源,CodeGen 將定義可以被 Turbo 模塊和 Fabric 使用的接口,另外 Codegen 會在構(gòu)建時生成 Native 代碼,減少運(yùn)行時的開支。

          「從上面四點(diǎn)可以看到 2022 年 RN 將迎來性能和體驗(yàn)上的躍遷,本次即將到來的全新架構(gòu)將解決 RN 多年以后被人詬病的各種根本上的設(shè)計(jì)問題」

          Skia

          另外還要介紹的內(nèi)容就是 react-native-skia ,目前它還處于 alpha release 的階段,但是它也給 RN 帶來的新的可能。

          ?

          眾所周知,F(xiàn)lutter 跨平臺的性能提升和解耦來自于直接使用 Skia 渲染而非系統(tǒng)控件,而如今 RN 也有類似的支持。

          ?

          react-native-skia 需要 react-native@>=0.66 的支持,而目前它上面的操作都還是十分原始的 canvas 行為,例如通過 Circle 繪制圓形,通過 blendMode 配置重疊模式等。

          import {Canvas, Circle, Group} from "@shopify/react-native-skia";
           
          export const HelloWorld=()=> {
            const width=256;
            const height=256;
            const r=215;
            return (
              <Canvas style={{ flex: 1 }}>
                <Group blendMode="multiply">
                  <Circle cx={r} cy={r} r={r} color="cyan" />
                  <Circle cx={width - r} cy={r} r={r} color="magenta" />
                  <Circle
                    cx={width/2}
                    cy={height - r}
                    r={r}
                    color="yellow"
                  />
                </Group>
              </Canvas>
            );
          };

          當(dāng)然它也支持直接使用 SkiaView ,然后通過 canvas 來繪制你需要的圖形:

          import {Skia, BlendMode, SkiaView, useDrawCallback} from "@shopify/react-native-skia";
           
          const paint=Skia.Paint();
          paint.setAntiAlias(true);
          paint.setBlendMode(BlendMode.Multiply);
           
          export const HelloWorld=()=> {
            const width=256;
            const height=256;
            const r=215;
            const onDraw=useDrawCallback((canvas)=> {
              // Cyan Circle
              const cyan=paint.copy();
              cyan.setColor(Skia.Color("cyan"));
              canvas.drawCircle(r, r, r, cyan);
              // Magenta Circle
              const magenta=paint.copy();
              magenta.setColor(Skia.Color("magenta"));
              canvas.drawCircle(width - r, r, r, magenta);
              // Yellow Circle
              const yellow=paint.copy();
              yellow.setColor(Skia.Color("yellow"));
              canvas.drawCircle(width/2, height - r, r, yellow);
            });
            return (
              <SkiaView style={{ flex: 1 }} onDraw={onDraw} />
            );
          };

          目前該庫支持 Image、Text、Shader、Effects、Shapes、Animations 等操作,而事實(shí)上該庫的實(shí)現(xiàn)和 Flutter 很是相似,比如:

          ?

          在 Android 上的 SkiaDrawView 其實(shí)就是 TextureView ,繪制邏輯是作者自己寫的 reactskia 上,這里只是借助了 TextureViewsurfaceTouchEvent 等的支持。

          ?

          如下圖所示,是關(guān)于使用 react-native-skia 實(shí)現(xiàn)的一段 Demo

          詳細(xì)可見:https://shopify.github.io/react-native-skia/

          可以預(yù)見目前的 react-native-skia 還有不少問題需要解決,但是它讓 RN 可以更高效地使用豐富的 Canvas 能力,對于 RN 的未來而言不免是一次不錯的嘗試。

          最后

          在這里就分享一份由大佬親自收錄整理的學(xué)習(xí)PDF+架構(gòu)視頻+面試文檔+源碼筆記高級架構(gòu)技術(shù)進(jìn)階腦圖、Android開發(fā)面試專題資料,高級進(jìn)階架構(gòu)資料

          這些都是我現(xiàn)在閑暇時還會反復(fù)翻閱的精品資料。里面對近幾年的大廠面試高頻知識點(diǎn)都有詳細(xì)的講解。相信可以有效地幫助大家掌握知識、理解原理,幫助大家在未來取得一份不錯的答卷。

          當(dāng)然,你也可以拿去查漏補(bǔ)缺,提升自身的競爭力。

          真心希望可以幫助到大家,Android路漫漫,共勉!

          如果你有需要的話,只需私信我【進(jìn)階】即可獲取

          的,大家可能很疑惑:“都 2020 年了,怎么現(xiàn)在還發(fā)布組件庫呢?”

          確實(shí),對于前端組件庫的大家庭來說,我們遲到了,但也請各位可以抽出幾分鐘看看一位初來乍到的新人的自我介紹:

          Zarm 是什么

          Zarm 是眾安科技基于 React、React-Native 研發(fā)的一款適用于企業(yè)級的移動端 UI 組件庫。

          Zarm 的優(yōu)勢

          • 組件多。Zarm 目前開源了 50 個組件,基本覆蓋常見的通用組件,并仍在持續(xù)更新迭代中。
          • 規(guī)范多
          1. 擁有完整統(tǒng)一的設(shè)計(jì)規(guī)范。
          2. 樣式命名采用了 BEM 的規(guī)范,內(nèi)部實(shí)現(xiàn)使用了 Css Variables + SCSS Mixins,這使得樣式維護(hù)的工作變得優(yōu)雅簡潔。
          3. 遵循嚴(yán)格的代碼規(guī)范,基于 airbnb 的 lint 封裝的 eslint 規(guī)則以及基于 stylelint 實(shí)現(xiàn)的樣式規(guī)范。

          • 依賴少體積小,極少的依賴三方庫,Gzip 壓縮后,全量組件只有 60kb 左右的大小。
          • 支持按需加載,zarm 默認(rèn)支持基于 ES module 的 tree shaking。

          • 擴(kuò)展性好,我們提供了內(nèi)置的基礎(chǔ)組件,可以方便地基于現(xiàn)有組件實(shí)現(xiàn)二次開發(fā)。比如我們的 Popup 組件就是所有彈層類組件的基礎(chǔ),Modal、Toast、Loading、ActionSheet、Picker、Select 等都是基于 Popup 組件實(shí)現(xiàn)。再比如 PickerView 組件就是滑動選擇類組件的基礎(chǔ),而Picker組件就是簡單的將Popup和 PickerView 結(jié)合而成。相信你也可以基于這些基礎(chǔ)組件開發(fā)出更豐富的業(yè)務(wù)組件~
          • Zarm 也會密切關(guān)注官方的更新,在發(fā)布的正式版中,我們已去除在 React17 中不再常規(guī)使用的生命周期,更新為最新的生命周期。
          • 響應(yīng)及時,目前在內(nèi)部開源的情況下,已有接近 3000 次的 commit,在及時響應(yīng) issue 的同時,我們也保持著快速的迭代。只要有問題,我們一定及時跟進(jìn),不會讓問題石沉大海。
          • 穩(wěn)定性好,Zarm 使用 Jest + Enzyme 做單元測試。單元測試覆蓋率超過 80%,并且在持續(xù)攀升中。

          • 友好的 typescript 支持,都 2020 年了,再不用 ts 的話世界末日真的就要來了。
          • 樣式使用 css 變量,支持一鍵換膚,自定義皮膚。

          Zarm 的未來

          在不久的未來,我們會推出:

          • 桌面端組件庫 Zarm-Web。
          • hpaPaaS 無代碼建站平臺(名字暫時保密)。
          • ......

          對不起,我們來晚了

          在各個前端團(tuán)隊(duì)或自己研發(fā)、或使用第三方組件庫的時代,我們將致力于把 Zarm 打造成體驗(yàn)更好的基于 React、React-Native 的一款適用于企業(yè)級的移動端 UI 組件庫。

          最后,非常感謝你的閱讀,也非常歡迎有興趣的同學(xué)加入我們共建更好的 Zarm!

          Github 開源地址:https://github.com/ZhongAnTech/zarm


          主站蜘蛛池模板: 一区二区三区免费在线视频| 福利一区国产原创多挂探花| 日韩精品一区二区三区国语自制 | 亚洲一区精品无码| 亚洲综合国产一区二区三区| 亚洲一区二区中文| 无码一区18禁3D| 一区二区三区四区国产| 人妻少妇一区二区三区| 亚洲一区精彩视频| 一区二区不卡视频在线观看| 91在线一区二区| 国产激情无码一区二区三区| 2021国产精品一区二区在线| 精品乱码一区内射人妻无码| 国产午夜精品一区二区三区小说| 无码精品黑人一区二区三区| 亚洲爆乳精品无码一区二区| 一区 二区 三区 中文字幕| 精品人伦一区二区三区潘金莲| 精品久久久久一区二区三区| 精品国产一区二区三区久久影院| 亚洲视频一区在线播放| 免费无码VA一区二区三区| 亚洲欧洲精品一区二区三区| 亚洲码一区二区三区| 日韩视频免费一区二区三区| 国产suv精品一区二区6| 一区二区三区www| 国产探花在线精品一区二区| 国产精品无码AV一区二区三区| 亚洲AV无码第一区二区三区| 91一区二区三区四区五区| 在线精品国产一区二区三区 | 精品乱人伦一区二区三区| 日本韩国一区二区三区| 99偷拍视频精品一区二区| 精品成人乱色一区二区| 91久久精品无码一区二区毛片| 国产一区二区福利| 国产精品亚洲产品一区二区三区 |