神族九帝's blog 神族九帝's blog
首页
网盘 (opens new window)
线报 (opens new window)
商城 (opens new window)
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 基础篇
  • 进阶篇
  • 高级篇
  • 计算机基础
  • 高频考点
  • 精简题
  • 综合问题
  • 复习题
  • vue
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • 更多
  • 网站
  • 资源
  • Vue资源
  • 收藏的一些API
  • 未来要做的事
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 导航
GitHub (opens new window)

神族九帝,永不言弃

首页
网盘 (opens new window)
线报 (opens new window)
商城 (opens new window)
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 基础篇
  • 进阶篇
  • 高级篇
  • 计算机基础
  • 高频考点
  • 精简题
  • 综合问题
  • 复习题
  • vue
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • 更多
  • 网站
  • 资源
  • Vue资源
  • 收藏的一些API
  • 未来要做的事
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 导航
GitHub (opens new window)
  • vue2源码学习

  • 剖析vuejs内部运行机制

  • TypeScript 入门实战笔记

  • vue3源码学习

  • 2周刷完100道前端优质面试真题

  • npm发包

  • 重学node

  • 前端性能优化方法与实战

    • 00 开篇词 开启刻意练习之路,进阶前端性能技术专家
    • 01 体系总览:性能优化体系及关键指标设定
    • 02 性能瓶颈点:从 URL 输入到页面加载整过程分析
    • 03 案例分析:移动端 M 站性能优化落地注意事项
    • 04 指标采集:首屏时间指标采集具体办法
    • 05 指标采集:白屏、卡顿、网络环境指标采集方法
    • 06 工具实践:性能 SDK 及上报策略设计
    • 07 平台实践:如何从 0 到 1 搭建前端性能平台
    • 08 诊断清单:如何实现监控预警并进行问题诊断
    • 09 优化手段:首屏秒开的 4 重保障
    • 10 优化手段:白屏 300m 和界面流畅优化技巧
    • 11 工具实践:如何进行性能专项测试
    • 12 理论分析:Hybrid 下的性能优化整体分析
    • 13 高级进阶:保证首次加载为秒开的离线包设计
    • 14 高级进阶:瞒天过海的骨架屏及 SSR 优化手段
    • 15 高级进阶:WebView 层及代码架构层面优化
    • 16 黑科技:详解预请求、预加载及预渲染机制
    • 17 横向对比:百度、阿里云、美团性能方案对比
    • 18 性能演进:RN、Flutter、小程序和 Enhance Hybrid
      • 19 成长之路:前端技术专业能力与业务产出平衡
      • 20 结束语 开启性能优化实践之路
    • webpack原理与实战

    • webGl

    • 前端优化

    • Web3

    • 更多

    • 学习笔记
    • 前端性能优化方法与实战
    wu529778790
    2021-09-20

    18 性能演进:RN、Flutter、小程序和 Enhance Hybrid

    前面讲的性能优化方案,基本都立足于 Hybrid。这一讲我们来聊聊多端场景下的性能优化方案——RN、Flutter 和小程序。

    RN 即 ReactNative,是 Facebook 开发的开源移动应用架构,它可以让开发者基于 Javascript 和 React.js 开发跨平台移动应用。近一年 RN 非常火,其优势之一是多端开发,另一个最大特点就是渲染性能,我曾使用 RN 做了一个个人中心解决方案,首屏性能可以提升 50%。

    Flutter 是一个由 Google 开发的开源移动方案,与 RN 类似,主要为 Android、IOS 系统开发应用。它的技术架构屏蔽了平台的概念,把多端优势在更底层解决掉了,同时渲染性能更好一点。

    除此之外,Flutter 最大的优势在于提升了开发效率。我曾在实际项目中实验过,相对于 iOS 和 Android 两端开发,它可以降低 40% 的开发成本。

    小程序则是一种不需要下载安装即可在微信平台上使用的程序,它主要为开发者在微信平台上提供服务。使用小程序进行优化时,不像 RN 和 Flutter 拥有良好的性能,需要我们额外做一些事情。下面我就一一为你详细介绍下。

    RN 原理及其性能优化

    一般在移动端开发中,我们会使用原生应用或者 H5,但它们都有不能忽视的缺点。如果使用原生开发的话,由于客户端发版和版本审核,迭代周期会比较长;而使用 H5 的话,它的性能体验又比较差,不如原生应用流畅。所以,为了解决这两个问题,RN 就出现了。

    RN 会把应用的 JS 代码(包括依赖的 framework)编译成一个 buddle.js(如 iOS 下 index.ios.bundle.js),它整体框架的目的就是解释运行这个 js 文件。如果是 js 扩展的 API,则通过调用 bridge 方法来调用 native 方法。在这个框架下,上线周期和 Hybrid 类似,

    但因为框架层负责跨平台的渲染,渲染效率比 Hybrid 好得多,前端开发者只需要关心如何编写 JS 代码即可。

    有关 RN 的环境搭建和基础使用,我就不多介绍了,这里重点来聊聊 RN 下的性能优化问题。

    2016 年初我使用 RN 改造个人中心页面,当时遇到了两个难题:

    1. Listview 无限下拉列表初始渲染慢,滚动过程中卡顿体验差的问题;

    2. 用户在拍照时,遇到的卡死的问题,根源是调用拍照控件时出现卡顿。

    第一个是 RN 的老大难问题了,我最初是通过官方提供的 Flatlist 来解决,但由于 Flatlist 追求比较一致的滑动体验,使用空白的 view 组件进行占位,如果你滑动比较快,会来不及渲染就会出现白屏。后来,我做了技术调研后,在 Native 侧封装了一个原生的ListView,通过 RN 层来调用解决了这个问题。

    第二个问题,调起照片控件时出现卡顿,后来定位发现,原来是 JS 调用 Native 照片预览时,出现了延迟。

    为什么会这样呢?

    目前的 RN 框架,是基于大量 JSON 消息序列化和反序列化来进行通信的。它的大致逻辑包括以下两段;

    • 从 JS 到 Native 通信,即当 JS 调用 RN 控件时,JS 会把它需要调用的 NativeModule 函数和 NativeModule 对应的名称参数用 JSON 序列化后,传递给 Native,Native 接着会提取并调用对应的 NativeModule 的方法;

    • 从 Native 返回向 JS 通信,Native 先通过 CreateInstance 将数据处理成 JSON,再传递给 JS ,JS 完成调用 JSModule,以实现 Native调用 JS 组件的能力。

    在通讯过程中,如果出现调用延迟,会导致操作后没反应情况的发生。

    这就需要通过周期性调用类似 ping 的方式来检测是否出现延迟。具体来说,在调用 ping 指令后对时间进行记录,如果时间超过某个阈值,就认为出现延迟了,阻塞延迟后,需要等待该进程结束,而非持续排队调用。

    解决过程中,还需要注意两点:

    • 原有 Hybrid 工程迁移到 RN 过程中,会发现很多新旧功能兼容问题,此时我们可以重新根据 RN 下的体验去设计页面功能,而不是盲目做功能拷贝;

    • 提前做好 RN 基础建设,打包编译和热更新流程,尽量和 Hybrid 下的基建体系保持统一。

    Flutter 及其性能优化

    当我们使用 RN 开发移动端应用时,会因为要适配 Android 和 iOS 两端,导致代码复杂度特别高的情况。而使用 Flutter 可以避免这一情况。为什么呢?因为 Flutter 自带的渲染引擎和视图,可以帮我们完成组件层的闭环渲染,避免了像 RN 一样还要在组件层和渲染层分别实现。

    请看下方 Flutter 架构实现图。

    图片1.png

    Flutter 框架整体上使用 Dart 语言来实现,并且有着清晰的分层架构。这个分层架构除了让我们调用 Flutter 时更便捷之外,还可以分层调用甚至修改每次层的实现。

    架构图中的 Foundation 层,提供了最基础的绘图、界面刷新,触屏等事件;Rendering 层由 Animation、Painting、Gestures 这几个子模块组成,它对外实现了完整的布局绘制功能,正是这一层让 RN 具备了跨平台渲染能力。

    在它上一层是 Widgets ,它是开发者最常接触的一层,也是实现跨平台能力的一层,主要包括文本、图片、输入框动画等。在 Flutter 中,通过这一层可以组合嵌套不同的控件,可以构建出任意功能,任意复杂度的界面。

    最上面的 Material + Cupertino 层提供了一系列控件(如 Material Design 和 iOS style 的控件),它主要用来保证两个平台(IOS 和 Android)上用户体验的一致性。

    正是通过这一层层架构,Flutter 内部闭环实现了跨平台组件、渲染等流程。

    那么,使用 Flutter ,前端的性能问题一般会出现在哪里呢?我们该如何进行优化?

    用户在使用 Flutter 业务中,遇到的性能问题主要有两大类:

    • 用户滑动操作不流畅,因为丢帧导致的卡顿;

    • 操作流程被中断,陷入等待,也就是页面资源加载时间过长。

    为了解决上述问题,我们选定页面滑动的流畅度(FPS)和页面加载耗时,作为性能指标。FPS指标的采集,一般借助 mChoreographer 和 CFRunLoop 来实现。但由于这两种方法都是在主线程上进行的,而 Flutter 的绘制是在 UI TaskRunner 中完成,在 GPU TaskRunner 中渲染,所以以往的 FPS 检测方法并不适用于Flutter。

    Flutter 官方也提供了 Performane Overlay,缺点是无法提供在线监控的性能指标。最后我参考了业界,采用 handleBeginFrame和 handleDrawFrame 之间的时间间隔来计算帧率。前者用来启动一个新帧,后者用于帧的绘制。

    具体是怎么做的呢?

    第一步,在使用 App 进行交互操作,开始时计时,1s 内打印下开始时间 startTime,然后在handleBeginTime 方法回调时进行记录,再在 handleDrawFrame 方法回调时进行记录,结束计时打印下 endTime,将 endTime - startTime 存储数组 PerfArr 中。

    第二步,计时达到 1s 后,计算刷新次数 PerfArr.length。PerfArr 中超过 16.6ms 的认为丢帧,如果连续 5 帧超过 50ms 则认为卡顿,单帧超过 250ms 则认为严重卡顿。

    第三步,根据卡顿进行预警即可。

    小程序及其性能治理方案

    我们在开发 Android 和 iOS App 时,H5 会出现白屏和页面切换不流畅的问题,与此同时,我们也希望 App 可以随时更新,而不需要上架审核。随着技术的发展,小程序作为替代方案就出现了。

    小程序分为微信、支付宝、百度、头条系等多种,在这里我以微信小程序为例介绍下。微信小程序是怎么解决的呢?它主要通过设计一套自己的 Web + 离线包方案来实现,这样既能保证跨平台实时更新,还能保证性能体验。

    同时,小程序还能禁掉一些不合适的标签(如外跳 URL 的 A 标签)和 API(如动态执行脚本的API),减少安全问题。此外它还能避免 JS 操作 DOM,从而提升渲染性能。

    以下是小程序的架构设计:

    图片3.png

    小程序的渲染层使用 WebView 进行渲染,开发者的 JS 逻辑运行在一个独立的 Jscore 线程中。

    渲染层提供了带有数据绑定语法的 WXML,逻辑层提供了setData 等 API,开发者需要更新界面时,通过 setData 把变化的数据传递过去,小程序框架会根据 Dom Diff 的流程把正确的结果更新在 DOM 树上。

    一般小程序的前端性能,我们主要关注首屏时间,也就是用户打开小程序到首屏加载完成的时长。

    2016 年我在做微信支付项目时,收到用户反馈,主程序加载慢。当时我先做了首屏时间的采集,通过 setData 结束时间 - 路由开始时间获取到,发现首屏时间一度超过 5s。为了解决这个性能问题,我们开始结合业务场景和架构图进行了定位。

    当时我们的小程序是放在微信支付的九宫格中的,大概有千万级的流量,公司很多业务都想使用这个流量,于是我们在小程序首页就增加了一个入口逻辑,随着业务增加,首页的代码量也越来越大。

    再看小程序的架构图。我们可以知道,小程序启动时,也分为逻辑层的启动和视图层的启动,逻辑层的启动主要是加载 JS 代码,视图层则是启动 WebView 对页面进行加载和渲染。这也增加了时间。

    经过这么一番分析,我们发现问题出在首页包过大上,它导致逻辑层加载过慢,首屏时间超标。

    最后是怎么解决的呢?我的做法是先整理和清理包资源,比如把小 icon 都统一从网络加载的方案,无用资源及时清除;然后采用分包加载的机制减少首屏时间。

    所谓分包加载,就是根据业务场景,将用户访问率高的页面放在主包里,将访问率低的页面放入子包里,按需加载。具体在这个项目中,我在主包只保留核心页面,如核心页面导航位及首页信息流等,其他内容(如积分种树功能、公益活动等)都放入子包中。启动时只加载主包,使用时再按需下载子包。这样主包从 1.2M 降低到 0.5M,首屏时间达到微信小程序下首屏时间标准的即 3s。

    这里面的注意事项就是,要在项目方案设计时,就做好代码和资源目录文件的划分,主要功能所依赖的资源,要放在主包里,子包的拆分不需要太细。如果用户在点击到子包目录时,感觉有卡顿,可以做一些预加载处理。

    小结

    好了,以上就是 RN、Flutter、小程序等的优化方案。在具体的实施过程中,我们遭遇了不少坑,最大的坑是 RN 方案接入期遇到的。我们在新技术生命周期的“早期采用者”阶段就已经介入了。

    图片2.png

    这个阶段 BAT 都没有大规模使用,出现问题后(如页面报错)需要去向 Facebook 开发同学提issue 去解决,往往解决一个问题就需要 2 周时间,业务往往等不及,严重影响了项目进入生产环境的进度。所以建议你以后在采用新技术方案时,尽量在上图的“早期大众”阶段再进入,这个时期很多常见的坑都蹚过了, Flutter 方案我们就是这么做的。

    下面给你留一个问题:

    你们现在使用的多端方案有哪些性能优化手段呢?

    好了,欢迎在评论区和我沟通,马上进入下一讲,前端技术专业能力与业务产出平衡。


    # 精选评论

    # **康:

    这里 Flutter 只提到性能指标的收集,有优化方案吗?

    #     讲师回复:

        Flutter这块儿,优化方案还在做的过程中,主要是卡顿优化,长列表优化和内存优化等

    编辑 (opens new window)
    上次更新: 2021/09/20, 16:50:45
    17 横向对比:百度、阿里云、美团性能方案对比
    19 成长之路:前端技术专业能力与业务产出平衡

    ← 17 横向对比:百度、阿里云、美团性能方案对比 19 成长之路:前端技术专业能力与业务产出平衡→

    最近更新
    01
    好玩的docker
    07-04
    02
    我的第一个NFT
    07-03
    03
    海外迅雷
    06-01
    更多文章>
    Power by vuepress | Copyright © 2015-2023 神族九帝
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×