前言

对于混合应用而言,性能问题一直被吐槽,虽然设备的内存的不断增大,很大程度上缓解了这个一问题,但是和原生应用来讲还是有很大区别,本人从Phonegap2.x开始,一直的探索和使用混合应用技术。

当时的2.x性能真是不怎么样,首次加载时间也比较长,后来phonegap被apache纳入旗下以后,更名为Cordova,可以说从此以后,性能问题得到了很大的改善,占用内存也越来越小,到如今使用的版本已经变为6.3.0,看得出cordova也一直在尝试缩小与native的差距。

不管一个平台如何,是好,是坏?很大程度上都取决开发人员的技术水平,所以如何开发一个高性能的混合应用成为了至关重要的问题。

对于大部分项目而言,都不是一锤子买卖,很多都是长期项目,长期项目就免不了版本的一次一次的更新迭代,可以业务逻辑变得越来越复杂,页面变的越来越多,动画越来越炫酷,数据量越来越大,面对种种问题,我们都需要解决,所以一个好的优化方案势在必得。

下面,就谈一下,这几年我再混合应用开发过程中尝试的优化方案。

部分内存数据移动至离线存储

影响速度的根本因素,几乎都在内存上,如果内存消耗过高,应用就会卡顿,甚至闪退现象。

所以建议内存方面应注意, 不要存大量的应用数据在内存中,我们可以选择离线数据库,比如pouchdb,当然部分必要数据还是要存的,看实际需求。

目前离线数据库框架都是基于websql,运行速度非常快, 所以必要情况下,可以选择数据离线存储,避免占用内存,因为混合应用的webview渲染本身已经消耗部分内存了。

加载速度优化

由于项目不断变大,势必会导致js bundle文件的不断扩充,文件大了,加载速度也就会变慢, 首要解决方案大概如下:

  1. JS压缩整合 (压缩所以js,整合一个文件)
  2. 图片压缩整合 (压缩图片,保证清晰度即可)
  3. CSS压缩整合 (压缩整合一个文件,减小大小)
  4. 巧用Splash 页面(设置3秒延迟,保证html加载完全)

如果不足以优化,就需要讲JS 文件整合成两个文件,从而使文件变小,不必要的的js bundle 可以使用h5 异步加载,提高效率。

例如:

HTML页面与原生View的无缝衔接

对于混合应用而言,很难达到htmL view和原生view的无缝对接,也就是说,使用起来恰似是同样的实现方式,在一个栈里边。

但事实, 原生view属于native的栈中,而html view属于另一栈中,两种形式的view分属于不同的世界, 而且在使用js调用原生应用,cordova存在线程阻塞问题。

如果下面这个需求,就不好实现了:

大概是,view1中点击按钮,调用扫描插件view2, 扫描出结果以后启动view3,当在view3点击back按钮,需要在返回扫描产检view2, 扫描插件view2点击back退回view1.

对于这个需求,无论是native 还是 html, 在一个栈中,都不是问题,非常简单,但是,不同栈里,就不太好实现了,当在view3点击back调用插件会阻塞掉线程,即便执行back,也无法回退的,最后,在view2点back 回退时候发现, view3闪一下,马上退回view1。

为了解决这个问题,需要用timeout简单实现一个异步的操作,问题就解决了:

setTimeout(function(){// to execute the native plugin action. eg. call view2
},100)

动画的使用

动画效果,是用户交互体验的根本,如果动画处理不好,就会使很大的问题。

比如进入一个页面后,需要执行一个大概三秒的动画效果,在这三秒内,可能无法触发任何click事件。

比如transform动画。

所以,当你的app中在进入页面两秒内发现点击事件不生效,你就要考虑一下这个页面是否有没有执行完的动画了。

巧用Cache缓存

对于angular这样的框架而言是没有页面缓存技术的, 但是部分应用场景中,页面缓存又在所难免,比如像ios tab view这样的底部导航view,是存在缓存的,如果我们可以取消,会非常不符合ios的设计规范。

从用户角度而言,通常情况这中tab view navigation是不需要重新加载数据的,这样的主页面,几乎时刻存在,从新加载会浪费过多的时间。

这里附上一个ionic的缓存方案:

$stateProvider.state('demo', {cache:true,url: '/demo',template: '<div></div>',})

上面代码中,通过路由功能对这个页面做了一个cache功能,同样可以禁止掉。

注意:ionic默认是有页面缓存的哦。

避免过多使用监听

监听操作,非常的好用,开发中带来了很多便利,但是于此同时也带来了一些弊端,即为内存的消耗,如果过多的创建监听,势必会占用很多内存。

所以在某些情况下我们可以避免使用监听操作:

比如:我们需要监听一个input输入框数值的变化:

通常来讲会是如下方案:

$scope.$watch('', function(new , old){})

但是这样就创建了一个监听操作。

我们也可以这样做:

<input type="text" ng-blur="action" />或者<input type="text" ng-change="action" />

合理使用HTTP

对于部分App, 在程序启动后,可能不止请求一个服务,可能会两个或者三个以上,如果需要等所有服务都请求完在进行页面跳转,实现起来就比较麻烦了。

如果一个请求完在请求另一个,时间势必会延长,影响用户体验。

我们可以采用如下解决方案,来自angular:

$q.all([async1, async2, async3...], function(res2, res2, res3 ....){})

http请求即为异步请求,所以以上方案就是异步并发请求,而且是等所有返回结果结束在进行统一回调。

这大大提升了请求速度,提升用户体验。

合理使用Native功能弥补JS的短板

JS是万能,但又不是万能的,混合应用的有些功能如果用js实现性能上会存在很多问题,比如:

  1. 拍照压缩
  2. 文件上传下载
  3. 网络状态监听

为了能够有更好的体验,我们就需要调用原生api实现此功能,并合理创建多线程处理,从而提高运行速度。

采用轻量级组件化框架技术

这几年下来,我使用的框架,还是比较多的,比如vue.js, ionic, avalon, SAPUI5, backbone, durandal, angular还有最新的react系列。

目前框架都在主推,高效轻量级的框架,效率高,性能好,加载速度快,易上手。

这些特性对于移动端同样适用。

所以,我们在进行混合应用开发时候,要选择轻量级的框架,切稳定,社区活跃的,保证遇到问题,有章可循。

这里建议的有: angular, ionic, backbone。

http://blog.csdn.net/jiangbo_phd/article/details/51761565

实现本地View的加载渲染

目前混合主要实现方式有两种:

  1. webview 加载本地html css, js , 图片文件,也就是说所有文件存在于手机app本地。
  2. 还有一种即为,html, css, js 图片文件部署在远程服务器上,通过url形式被webview加载。

两种方式各有优缺点,第一种加载速度快,适用于离线app. 第二种加载速度慢,使用与web app。

看你选择了。

Infinate动态加载数据

对于前端无穷渲染list数据是存在一定问题的,angular最大的问题就在这个地方,angular的ng-repeat,无法渲染大量数据,否则的页面会出现假死的状态。

对此,同样存在解决方案,也就是Infinate无穷加载,当滑动到底部,会动态监测,然后load更多。

附上一个简单的实现方案,采用ionic技术框架:

<ion-content ng-controller="MyController"><ion-list>........</ion-list><ion-infinite-scrollon-infinite="loadMore()"distance="1%"></ion-infinite-scroll>
</ion-content>
function MyController($scope, $http) {$scope.items = [];$scope.loadMore = function() {$http.get('/more-items').success(function(items) {useItems(items);$scope.$broadcast('scroll.infiniteScrollComplete');});};$scope.$on('$stateChangeSuccess', function() {$scope.loadMore();});
}

请求数据并渲染DOM优化方案

现在几乎所有的系统都是前后端分离的,也就说需要通过ajax请求数据后在渲染到页面上。

目前主流的框架都会支持很多的绑定方式,比如:

  1. 双向数据绑定:
  2. 单向数据绑定
  3. 一次性数据绑定

如何使用合适的绑定方式决定了我们内存消耗的多少。

上面三种方式消耗状态: 双向> 单向> 一次性

那么什么时候该使用什么样的绑定方式呢?

举个例子:

  1. 用户登陆 (双向,因为要获取用户名和密码在controller)
  2. 新闻详细信息显示(一次性,因为不需要再更新数据)
  3. 表单验证结果显示信息(单向,因为需要根据controll信息动态更新检验结果状态)

避免创建过多的window全局对象

学过JS的同学都知道window即为全局对象,是任何一个地方都可以调用到的,也会有老程序员告诉新人说:“你不要污染了全局空间”。

例如Angular这样的框架,同样有个全局属性“$rootScope”, 也是我们在任何地方都可以使用的。

如果项目过多的使用了这样变量:

一. 是会导致全局变量的混乱不堪,无法维护。
二. 不使用时候,无法回收这个变量,垃圾变量占用内存。

尽量避免使用JS控制Dom样式

最近两年,Angular是非常火热的框架,所以本人使用angular也会比较多一点,在这个框架中,有一个属性是可以动态控制dom样式的,叫ng-class, 可以说非常的好用,刚开始时候变肆无忌惮的使用起来。

后来发现运行起来多个ng-class控制时,或者在ng-class中使用个属性,并使用===, 三目运算符进行判断,最终导致页面闪动的状态,也就是效果不佳。

附上一个简单的例子:

<div ng-class="{{'customStyle':flag ==== customFlag}}">
</div>

避免过度使用阴影和梯度和3D渲染

最近尝试了一下three.js这个框架,主要是想做3D图像,运行在浏览器端没有任何问题,但是在手机上,发现运行明显下降,运行一段时间后,手机发热,所以我们在项目中,尽量不要过多的使用3D这些特效,如果使用,要及时销毁,以免占用过多系统内存。

对于简单的CSS 3D旋转效果, 没有大问题, 大部分手机足以应付得了。

比如下面这段代码:

div
{
transform: rotateX(120deg);
-webkit-transform: rotateX(120deg); /* Safari 和 Chrome */
-moz-transform: rotateX(120deg);    /* Firefox */
}

避免使用setInterval对插件进行频繁调用

对于cordova插件运行机制,很多新人并不是很清楚,也并没有很多人去编写自定义插件, 一个插件的调用流程大概如下图所示:

所以,一次调用过程,会花费较长的时间, 这个过程中,由于JS的单线程异步操作,此时通过JS调取,会阻塞线程的继续运行。

如果此时,频繁的调用插件,应用内存会骤然上升,后果会crash掉。

及时升级优化Cordova Platform

我们都知道移动系统的更细速度异常的快,andorid每年一个大版本, IOS也是如此,每年都会推出一个大版本,每一个版本的改变可大可小,但是对我们混合应用还是有一定影响的。

其中webkit的更新最为明显,毕竟混合应用使用的是webkit做UI渲染嘛。

最近就遇到一个问题,当IOS 更新到10, android更新到6以后,总会有一些莫名的问题。显示的多少会有些差异。

解决方案是,对Cordova Platform 做一个升级。

ios-platform —> 4.2.0

android-platform —-> 5.2.0

于此同时也对JS库做了一个版本升级,以便支持最新的webkit.

尽量不去渲染不需要显示的DOM

有一部分app在设计过程中,view的部分信息是不需要或者不经常显示的,也就是这部分信息根据用户行为是可有可无的,但是这个部分信息在此页面可能dom元素又非常之多,层次也会比较深。

如果我们默认就绘制dom元素,肯定会花费一些时间。

这种情况下,我们往往不去渲染,等需要的时候在渲染,所以这种实现方式很大程度上提升了渲染的速度。

下面说一下我再angular工程中的实现方案, 采用了ng-if解决这个问题,简单容易:

<div>this is need to show<div ng-if="false">this is not need to show</div></div>

使用canvas优化图片加载速度

通常使用Img在移动端渲染图片,速度往往不是很理想,会显示空白,这种情况我们通常会使用canvas进行优化,具体代码如下:

使用过程要注意,只有图片加载完成后才能显示出来,否则会无效,这里用到了回调onload方法。

<head>  <title></title>  <script type="text/javascript" src="jquery-1.7.1.min.js"></script>  <script type="text/javascript">  $(function () {  var c = document.getElementById("myCanvas");  var cxt = c.getContext("2d");  var img = new Image();  img.src = "./images/richard.jpg";  img.onload = function () {  cxt.drawImage(img, 0, 0);  }  });  </script>
</head>
<body>  <canvas id="myCanvas" width="1024" height="768" style="border: 1px solid #f00;">Your browser does not support the canvas element.  </canvas>
</body>  

清除不需要的历史View

如果你的app页面越来越多,运行起来对内存的占用多少会有一定的影响,对于移动app,就需要我们尽量清除已经不再需要的view,比如注册流程所有的页面,比如slide导航,注册信息页,一旦注册完成,就需要删除所有的view历史。

再比如登陆,如果登陆成功也需要remove.

还有需要定时显示的banner等页面,显示过了,可能就不再需要了,这时候也需要清除掉。

下面说一下,我用ionic做过工程的相关方案:

if(this.$ionicHistory.backView()){ //获取上一个是哪个页面this.$ionicHistory.clearHistory();  //clear
}

动态刷新页面,为开发增添乐趣

对于多页面,复杂一些的项目工程,往往我们编译会花费较多的时间,记得我做过一个android native的项目,由于项目比较大,每次使用android studio编译都要花2分钟左右的时间,非熬人,对混合项目也不例外。

开发过程中,我们往往需要快速查看效果,实时浏览编译状态,所以就需要动态刷新了,说一下我采用的技术。

主要采用gulp + browserSync+ watchify来监听动态编译,实时加载,速度还是很快的,主要代码如下:

'use strict';var config      = require('../config');
var browserSync = require('browser-sync');
var gulp        = require('gulp');
var url         = require('url');
var proxy       = require('proxy-middleware');gulp.task('browserSync', function() {var proxyOpts = url.parse(config.backendUrl);proxyOpts.route = '/api';var browserSyncConfig = {port: config.serverport,server: {baseDir: config.dist,middleware: [proxy(proxyOpts)]},logPrefix: 'MyDemo',browser: ["google chrome"],minify: false,notify: false};browserSync(browserSyncConfig);
});browserSync.reload({ stream: true, once: true })gulp.watch('path',   [task]);

前端代码工程化

前端代码工程化,今年被唱的很热,都在提这个概念,目前来看,一人独大的时代已经过去了,更多的团队协作开发,所以一个工程化代码是非常有必要的。

主要包括以下几个方面:

  1. 有意义的变量命名,遵从驼峰命名法或者团队内部命名法则,统一规范。
  2. 使用JSLint对代码进行检查,所以人统一一个标准。
  3. 采用构建工具对工程进行自动化部署,减少操作步骤,比如使用npm command, gulp ,grunt webpack等等。
  4. 合理编写注释代码,方便阅读及他人接手,编译后切记要remove掉,因为对于产品环境,这些注释没有任何意义。
  5. 使用标准的代码仓库,比如git, bitbuket等等, 提交代码进行comment, 合理创建子分之,保证多人开发协作无冲突。
  6. 代码组件化或者模块化,争取做到一人一模块。一模块一个文件包或者一个文件,这样可以保证彼此没有冲突。
  7. 保证团队每个人对代码工程使用,烂熟于心,方便管理及升级。
  8. 任命技术负责人,负责代码统一管理,版本合并,产品发布。

采用实时云更新技术对app升级

对于部分项目需求,用户不行频繁升级app, 的确这样也比较麻烦,这里我采用CodePush对混合应用代码进行云部署,不需要更新app, 既可以部署业务逻辑到用户的手机上,也可以根据用户需要定义所需的功能。

更多信息大家可以参考这篇文章:

http://blog.csdn.net/jiangbo_phd/article/details/52692320

使用Android Studio 和 Xcode性能查看工具

如果查看app内存消耗,是很多人关心的问题,这里我采用Android Studio 和Xcode性能工具进行查看测试,可以随时查看项目运行状态,并作出调整。

注意:项目需要的debug的运行状态。

Android:

IOS:

WebStorm工具使用优化

前端开发工具这几年最火爆的,无疑是Sublime, WebStorm, Atom, visual studio code, 其中Atom, Visual Studio code作为一款开源的IDE, 是当先最为流行的, 支持很多酷炫的样式和各种的自定义插件。

但是,说起来,这几年用的最多的,非常喜欢的一款工具就是WebStorm, 它可以说是一款集成的工具,支持很多H5框架,但确实收费的。

伴随着项目工程的越来越大, 项目更是用了npm bower这类库管理工具,到整个工程文件愈发庞大,有时候写着代码,工具就死掉了,非常不happy, 探索一番,找到如下解决方案。

打开我们的工程, 找到WebStorm的preference属性后,搜索Directories, 看到下面这个截图,右键Exclude一些文件包,比如node_modules, bower_components, platforms, www等等。

然后点击apply ⇒ ok,就好了,主要原理就是不要加载过大的工程文件,否则工具会吃不消的。

总结

混合应用的开发之路,并不是很容易,个人认为它的难点和复杂度要远远高于native和web,因为我们要掌握的东西实在太多了。

个人微信公众号

Hybrid移动应用在多页面大数据复杂业务背景下的优化实践方案相关推荐

  1. 大数据量高并发的数据库优化(转载)

    对其进行处理是一项艰巨而复杂的任务.原因有以下几个方面: 一.数据量过大,数据中什么情况都可能存在.如果说有10条数据,那么大不了每条去逐一检查,人为处理,如果有上百条数据,也可以考虑,如果数据上到千 ...

  2. 【2016年第6期】大数据时代空间科学领域的科研信息化实践与成果

    邹自明,佟继周,熊森林,胡晓彦,纪珍 中国科学院国家空间科学中心,北京  100190 摘要:随着人类对空间探索的拓展以及对空间认知的加深,空间科学探测大工程任务相继推进.实施,催生了空间科学领域大数 ...

  3. IDC:全球大数据和业务分析收入预计到2019年突破1870亿美元

    根据IDC新的全球半年度大数据和分析开支指南,全球大数据和业务分析收入将从2015年的1220亿美元增加到2019年超过1870亿美元,在5年间的增幅超过50%.这个新的开支指南在IDC此前的预期基础 ...

  4. 大数据时代数据库-云HBase架构生态实践

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 2018第九届中国数据库技术大会,阿里云高级技术专家.架构师封神(曹龙)带来题为大数据时代数据库-云HBase架构&a ...

  5. 千万级别数据查询优化_MySQL大数据量分页查询方法及其优化

    MySQL大数据量分页查询方法及其优化 ---方法1: 直接使用数据库提供的SQL语句 ---语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N ---适 ...

  6. 大数据工作流_大数据和人工智能时代下的数字化工作流

    点击上方"Bentley软件"可以订阅哦 本文作者 Bentley 软件公司 高级技术经理 赵顺耐 大数据.人工智能以及与之相伴相生的物联网已经成为现代社会的运行方式,信息技术的急 ...

  7. 生物效应大数据评估聚类算法的并行优化

    生物效应大数据评估聚类算法的并行优化 彭绍亮1,2,杨顺云2,孙哲1,程敏霞1,崔英博2,王晓伟2,李非3,伯晓晨3,廖湘科2 1. 湖南大学信息科学与工程学院&国家超级计算长沙中心,湖南 长 ...

  8. 大数据和人工智能时代下的运筹学

    首发于[运筹帷幄]大数据和人工智能时代下的运筹学 大话"人工智能.数据科学.机器学习"--综述 1 2 个月前 作者系美国克莱姆森大学运筹学硕士,Ph.D. Candidate,师 ...

  9. mysql一样的查询在我本地很快但是线上很慢_MySQL大数据量分页查询方法及其优化...

    MySQL大数据量分页查询方法及其优化 ---方法1: 直接使用数据库提供的SQL语句 ---语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N ---适 ...

最新文章

  1. 2018年第一场省赛:黑龙江省智能车邀请赛
  2. 在Linux上编写并运行Python文件
  3. 使用RNN预测股票价格系列二
  4. UML总结---UML九种图关系说明
  5. 联想计算机主机编号,联想如何查找主机编号
  6. Fullpage:基础学习
  7. Eclipse技巧一:还原视图和编辑器
  8. InfoPath2003 教程
  9. 服务器更新维护尚未全部完成,【已开服】11月21日全部服务器更新维护公告
  10. Making a Kali Bootable USB Drive
  11. 电脑版微信防撤回插件
  12. ZEMAX | 绘图分辨率结果对光线追迹的影响
  13. 妈妈再也不用担心我的博客访问量了(一个可以刷博客访问量的小程序java)
  14. linux 文件锁 超时,Linux中的两种文件锁——协同锁与强制锁
  15. 麻木的踏实,但丧失了真实
  16. C++实现TTS文字语音朗读Microsoft Speech SDK
  17. (十三)Java工具类StringUtils中strip、stripStart、stripEnd剥离方法源码详解
  18. FL Studio教程之Wasp XT合成器功能介绍
  19. python股票数据分析实例_Python之简单股票数据分析
  20. 从源码分析PHP的SESSION实现机制

热门文章

  1. 英文求职信个人资料常用语
  2. PHPMailer实现QQ邮箱发送邮件
  3. 学习POSIX和C++多线程开发
  4. 本地生活O2O系统生活通O2O系统开发介绍
  5. UNITY 非人型动画 IK
  6. Pycharm--flake8的配置使用
  7. 基于Java实现简单亚马逊爬虫
  8. 这张图,若你看到线是弯的,眼睛就可能出了问题!还测老花、近视、色盲
  9. 软件6月促销,Melodyne,Magix,Eventide,iZotope,Krotos
  10. centos7下安装vimplus以及出现的问题