快应用开发优化技巧
栏目: JavaScript · 发布时间: 5年前
内容简介:2018年3月,华为、小米、OPPO等九大手机厂商共同发布了快应用。快应用标准由主流手机厂商组成的快应用联盟共同制定,其拥有传统app的应用体验,同时又具备无需安装、即点即用的特点。其实,早在2013年,百度曾推出了轻应用,2017年,腾讯又推出了小程序,之后,阿里也推出了支付宝的小程序。业务细节上,它们各有不同,但大体上定位是类似的,如同当年CS架构转向BS架构一样,这种无需安装、即点即用的应用形式,正在成为app市场新的趋势。闲言少叙,书归正传。本文的目的,是为了让大家了解到快应用开发常用的优化手段,提
2018年3月,华为、小米、OPPO等九大手机厂商共同发布了快应用。快应用标准由主流手机厂商组成的快应用联盟共同制定,其拥有传统app的应用体验,同时又具备无需安装、即点即用的特点。其实,早在2013年,百度曾推出了轻应用,2017年,腾讯又推出了小程序,之后,阿里也推出了支付宝的小程序。业务细节上,它们各有不同,但大体上定位是类似的,如同当年CS架构转向BS架构一样,这种无需安装、即点即用的应用形式,正在成为app市场新的趋势。
闲言少叙,书归正传。本文的目的,是为了让大家了解到快应用开发常用的优化手段,提升对应用代码整理的组织能力,合理拆分功能模块,从而使项目更易维护,提高工作效率。至于如何搭建开发环境,开发流程以及系统api的描述,大家均可在快应用的官方文档中找到。本文将介绍快应用开发的优化技巧。
快应用开发采用前端技术栈,其优化方式主要可从以下四方面进行:
- 数据共享
- 性能优化
- 错误处理
- 结构优化
数据共享
在快应用开发中,开发者需要了解页面与APP之间,页面与页面之间的数据共享方式。其实不止快应用,任何前端工程都需要考虑这个问题,如react开发中,引入redux可方便统一管理数据源,在快应用开发中,可以通过使用框架API或使用全局变量global两种方式实现数据共享。
1. 框架API
开发者可以在页面ViewModel中,通过this.$app.$def获取APP上定义的数据及方法。
但这种方式的缺点在于需要依赖ViewModel实例,然而,很多全局方法与生命周期无关。全局变量global作为独立于应用生命周期的引用,理应成为开发者的首选。
2. 全局变量global
在app.ux、${anyPage}.ux中,开发者都可以使用变量global。然而,页面与APP之间,页面与页面之间的变量global并不相同,引用的值指向不同的对象;虽然不相同,但它们的原型都指向同一个全局的对象。因此,开发者可以在这个全局对象上定义变量,这样在任何JS中均可访问。同样,这种方式也存在缺点,比如存在污染全局环境,在复杂场景下容易引发难以复现的BUG等问题。
性能优化
1. 更合理的Dom结构
Dom节点是构成页面最基本的元素,尽量使用符合语义的标签,同时减少Dom层级结构会对页面的可读性及性能都会有明显提升。
2. 更有效的选择器
快应用的开发框架支持后代选择器,这对开发者提供了很大的便利,但与此同时,后代选择器的性能损耗是相对较大的,如使用不得当,会对页面性能造成较多损耗。
我们首先要知道,CSS选择器是 由右向左解释 的。看以下选择器
#container > a {font-weight:blod;}
对于很多刚开始了解css的朋友来说,通常会认为,该选择器先找到id为container的元素,然后将字体加粗效果应用到直系子元素中的 a 元素上,应该是个高效的选择器。然而事实并非如此,浏览器首先会便利页面中所有的a元素,然后筛选出父元素id为container的节点。所以这个看似高效的选择器,其实也是花费了不少的开销。
了解到这个规则后,对于后代选择器的使用,我们建议做到以下几点优化。
- 避免使用组件名称作为后代选择的最后一项匹配规则,越是基础的组件,复用度就越多,越是要避免。如: .container #doc text { ... };否则每个text组件渲染时都会遍历匹配一次
- 减少后代选择的层级数量,层级越深,单次匹配耗时则成指数式增长。
- 后代选择中最后一条匹配规则的定义名称尽量唯一,如:.container #doc .doc-item .doc-name-zh{ ... }
3. 图片优化
在前端开发中,图片通常占据了较大的空间。较多的图片资源也意味着较多的http请求,在相同带宽条件下,下载一个200k的图片,一定比下载两次100k的图片速度更快。建议可以做几下几点优化。
- 使用CSS Sprites,其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background-repeat”,“background-position”的组合进行背景定位,这种方式最大的优点就是减少了http请求,大大提高了网页性能。话说回来,这种方式也有缺点,比如开发起来会相对麻烦。
- 对于页面上简单的图标文件,可尽量使用css3实现,或矢量图代替,这样也能明显减少图片占用的空间,提高性能。
- 避免图片压缩,如果页面中用不到较大的图片,就完全没必要通过css去压缩图片以适应需求。直接使用小图或其他可替代方式更加明智。
4. 简化ViewModel的data属性
数据驱动是当下流行的前端开发形式,在快应用中也是如此。在ViewModel的定义中,data属性主要承担数据驱动的数据定义,会对赋值的data中每个属性进行递归式的定义。因此,属性定义语义结构越清晰且数量越少,则质量越高。
例如,当我们发出fetch请求,返回结果中包含了很多数据,而前端需要显示的数据只是其中很少一部分,则在该页面的data中,就只需要定义前端需要显示的数据即可,如下面的示例代码片段。
// fetch请求返回的数据,数据量大,而data中只需要其中部分数据 const tradeInfoList = [ { "_id" : "5c31aa2a565e9938214da13b", "currentPrice" : 1, "tradePrice" : 1, "userId" : "admin", "tradeAmount" : 600, "stockInfo" : { "code" : "000008", "name" : "股票8", "price" : 1, "des" : "描述8" } }, { // ... } ] export default { data () { return { list: [] } }, onInit () { // 返回页面中需要的对象属性,过滤其他属性 this.list = tradeInfoList.map(item => { userId: item.userId, tradePrice: item.tradePrice }) } }
5. 懒加载
懒加载是一种通用的优化手段,传统H5页面中的懒加载,指的是页面即将进入屏幕可视区域时,才加载资源,渲染页面。这样,给用户直观的感受就是,页面加载速度变快了。在快应用开发中,可使用指令或事件触发来实现懒加载。
比如很常见的场景,一个包含list组件的页面,我们开始只渲染前十条数据,当页面下滑至某位置时,触发加载更多来完成渲染。
错误处理
前端开发中,一旦程序执行出错,就会报出JS异常弹框。
1. 访问null或undefined的属性
以上的这种错误可能是最常见的一种了,在稍微复杂的业务逻辑代码中,多加判空条件,是避免这种错误的最简易方式。即便某些数据在定义时是必须存在的,但我们无法完全保证,存在各种原因导致这些数据为空或undefined。保证代码的严谨性,是应对不确定性异常的根本方式。当然有些稍微复杂的情况下,需要特殊处理,如后两种场景。
2. JSON.parse解析出错
这种错误也十分常见。当我们转换一个JSON字符串时,如果这个字符串的格式并不是一个标准的JSON格式,那转换肯定失败。可以在JSON.parse()时,使用try-catch进行包裹,以便对错误信息进行分析,如
当然,在每处JSON.parse()的地方都执行try-catch会有些麻烦,更推荐的方式是,在app.ux中提前代理JSON.parse(),使用try-catch包围,如
export function parseProxy() { const rawParse = JSON.parse JSON.parse = function (str, defaults) { try { return rawParse(str) } catch (err) { console.error( ` JSON解析失败:$ {str}, $ {err.stack}` )return defaults } } }
3、ViewModel回调函数异常场景
用户打开PageA,然后在该页面中执行接口方法(如fetch请求),然后立即跳转到PageB;此时接口的回调函数返回,但PageA已经出栈销毁,此时,执行开发者传递的回调函数报错。
这是由于,回调函数中访问了一些data数据等,而这些ViewModel的数据属性已经伴随着页面销毁而删除了,所以引起报错。对于这种异常,通常可采用以下方式解决。
A. 在回调函数执行之前,通过ViewModel对象的$valid、$visible判断页面状态
B. 在Function.prototype上定义方法,关联到每个回调函数绑定ViewModel实例。
/** * 在Function原型上定义bindPage方法:将回调函数绑定到页面对象,页面不可见或者销毁时,不执行回调函数 */ export function bindPageLC () { Function.prototype.bindPage = function (vmInst) { const fn = this return function () { if (!vmInst) { throw new Error(`使用错误:请传递VM对象`) } if (vmInst.$valid && vmInst.$visible) { return fn(...arguments) } else { console.info(`页面不可见或者销毁时,不执行回调函数`) } } } }
在${anyPage}.ux中,通过fn.bindPage(this),在回调函数上绑定ViewModel实例
export default { data () { return {} }, request () { // 调用bindPage(this)返回:绑定了页面对象的回调函数,当页面不可见或者销毁时,不执行回调函数 fetch.fetch({ success: function(ret) { // 数据操作等 }.bindPage(this) }) } }
C. 通常在页面发送请求时,页面需要添加loading处理,以防止用户在此时进行其他操作,当然这种方式是从业务角度规避了这个异常。不过确是一种很常用的方式。可结合方式B以保证代码严谨性。
结构优化
结构优化的目的是减小页面以及整体rpk包的体积,减少冗余代码
常用的手段有以下几项:
A. 在app.ux中引入常用的JS库,并暴露给每个页面使用;可以避免每个页面在打包时对JS的重复定义
B. 项目内部的代码抽象封装,如封装常用的 工具 类函数,封装统一的Fetch请求方法,这些封装可作为公共方法提供给各个页面,便于维护的同时,也有效降低了代码量。
结尾
优化的目的是为了提高代码的可维护性以及应用性能,可以说,正是多种多样的优化手段,让逻辑性极强的代码变的充满艺术性。为了越发优雅地完成编码,我相信这个话题会一直探讨下去。
【责任编辑:张燕妮 TEL:(010)68476606】
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 让云应用开发更高效的五个小技巧
- 应用开发的流程
- 让开发者专注于应用开发,OpenCenter 3.0 开发者预览版发布
- 让开发者专注于应用开发,OpenCenter 3.0 开发者预览版发布
- RealityKit 增强现实应用开发
- TLS应用开发相关知识
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。