什么是小程序
小程序页面实质上是网页,应用了 hybrid 技术进行原生与 web 的混合开发,hybrid 技术应用 webview 做渲染,通过
js bridge
作为 web 与 native 的数据交互桥梁
- 应用技术栈与网页开发是统一的,都用到 HTML、CSS、JS
区别:不反对浏览器 API,比方 window、document,只能应用微信提供的 API
微信小程序的倒退历程
-
微信小程序状态
- 小程序更像是公众号开发的降级
- 晚期微信通过 sdk 形式加强了开发者开发公众号网页的能力,小程序的诞生是微信迈向平台化超级 app 的业务行为,并且帮忙用户更好的实现了「轻量级 APP」
-
开发规范
- 最后微信小程序本人定义了一套“规范”,最开始的框架没有组件、npm、和 web 生态重大脱节
- 因为非凡的双线程模型与四不像语法,小程序凋谢只是对三方业务的凋谢
-
商家涌入
- 小程序业务的开放性 -> 平台型 app
- 比方:支付宝小程序、百度、淘宝、360、快利用
- 小程序设计的目标:大多数抉择了和微信相似的架构,框架,更多不是从技术角度思考,而是想尽可能蹭微信小程序的福利,让开发者更快的投放到本人的平台
微信小程序框架
目录构造每个页面文件夹都蕴含了 wxml、wxss、js、json 几个后缀的文件,别离是模板文件,款式文件,js 脚本文件,json 页面配置文件。在目录最外层还有全局的 app.js、app.json、app.wxss
小程序类型利用的技术选型
渲染页面的技术计划
- 用纯客户端原生技术渲染
- 用纯 web 技术渲染
-
用客户端原生技术与 web 技术联合的混合开发 (hybrid) 渲染
计划比照
- 开发门槛:web 门槛低,原生也有像 RN 这样的框架反对
- 体验:原生体验比 web 好太多,hybrid 在肯定水平上比 web 靠近原生体验
- 版本更新:web 反对在线更新,如果小程序用原生开发,则须要打包到微信一起审核
-
管控与平安:web 可跳转或是扭转页面内容,存在一些不可控因素和平安危险
计划确定
- [x] 小程序的宿主环境是微信等手机 app,用纯客户端原生技术来编写小程序,那么小程序代码每次都须要与手机 app 代码一起发版。所以该计划不可取
-
[x] web 反对有一份正本资源包放在云端,通过下载到本地,动静执行后即可渲染出界面,但纯 web 技术在一些简单的交互上可能有性能问题。所以该计划不可取
- 在 web 技术中,UI 渲染跟脚本执行都在一个单线程中执行,这就容易导致一些逻辑工作抢占 UI 渲染的资源
-
[] 两者联合的 hybrid 技术来渲染小程序,用一种近似 web 的形式来开发,并且能够实现在线更新代码
- 扩大 web 的能力,比方输入框组件 (input、textarea) 有更好的管制键盘的能力
- 体验更好,同时加重 webview 的渲染工作
- 用客户端原生渲染内置一些简单组件能够提供更好的性能
双线程模型
小程序的渲染层和逻辑层分为两个线程治理
-
视图层(Web View) -> WebView 进行渲染
- 界面渲染相干的工作都在 WebView 线程里执行,通过逻辑层代码区管制渲染哪些界面。一个小程序存在多个界面,所以视图层存在多个 WebView 线程
-
逻辑层(App Service) -> JsCore 线程运行 js 脚本
- 创立爱你一个独自的线程去执行 js 代码,在这里执行的都是无关小程序业务逻辑的代码,负责逻辑解决、数据申请、接口调用等
- JSBridge:下层开发与 Native(零碎层)的桥梁,使小程序可通过 API 应用原生的性能,且局部组件为原生组件实线,从而有良好体验
设计目标:为了管控和平安等问题,阻止开发者应用一些,例如浏览器的 window 对象,跳转页面,操作 DOM、动静执行脚本的开放性接口
应用沙箱环境提供纯 javascript 的解释执行环境
- 客户端零碎,在 pc 运行时用 javascript 引擎执行 js 代码
- ios:在 ios 零碎时应用 ios 提供的 Js core 框架执行 js 代码
- 安卓:在安卓零碎时应用腾讯的 x5 内核提供的 JsCore 执行 js 代码
数据驱动视图变动
问:js 逻辑代码放到独自的线程中运行,在 WebView 线程无奈间接操作 DOM,开发者如何实现动静更改界面
DOM 的更新通过简略的数据通信来实现,逻辑层和视图层的通信由 native(微信客户端)做直达,逻辑层发送网络申请也经由 native 转发。
graph LR
对象模仿 DOM 树 --> 比拟两颗虚构 DOM 树的差别 --> 更新有差别的实在 DOM 树
- 在渲染层把 wxml 转化为对应的 js 对象
- 在逻辑层产生数据变动的时候,通过宿主环境提供的 setData 办法把数据从逻辑层传递到 native,再转发到渲染层
- 通过比照,更新实在 dom 内容
总结:这部分和 mvvm 框架相似,转化了 ast 树,通过 native 创立了虚构 dom,通过 setData 的办法更新数据,再通过 native 做了 diff 差异化更新实在 dom 树
事件处理
微信做了非凡的解决,将所有的事件拦挡后丢到逻辑层交给 js 解决
- 代码形容交互事件
- 视图层用户交互触发事件
- native 拦挡丢给逻辑层
- 逻辑层收到回调处理事件
事件的派发解决包含事件捕捉和冒泡两种:
交互流程就如同上述的数据驱动视图变动一样,native 拦挡丢给逻辑层后,通过 js 响应事件,通过 setData 批改数据,虚构 dom 发生变化,native diff 更新实在 dom
运行机制
- 冷启动:用户首次关上或者小程序被微信被动销毁后再次关上的状况(当手机零碎五秒内两次以上内存告警,小程序会被动销毁),此时小程序须要从新加载启动
- 热启动:退出用户曾经关上过某小程序,在肯定工夫内 (目前是五分钟) 再次关上该小程序 (小程序前后台切换),此时无需重新启动
留神 - 小程序没有重启的概念
小程序框架比照
小程序原生语法
- 目前小程序曾经可能做到前端工程化,并且植入前端生态中已有的一些理念,比方状态治理,CLI 工程化等等
-
前端能力根本在小程序上能够复用,比方状态治理,柯里化治理组件状态,ts 等
增强型框架
指小程序引入 npm 后,有了更凋谢的能力所带来的收益
以微信小程序为例,腾讯开源了 omi 框架
- 整体保留了小程序现有语法,在此之上对它进行了裁减和加强
- 比方引入了 computed hook,比方能间接通过
this.store.data.logs[0] = 'changed'
批改状态,彻底将微信小程序 vue 化
转换型框架
可能 一码多端 的框架,比方 rax、taro、uniapp,让开发者简直不必感触小程序原生语法,更大程度对接前端已有生态,只是最初构建产物为小程序代码
这些框架理论都是通过转换产物 1:1 转换成对应的小程序代码
graph LR
开发者代码 --> AST 树 --> 新 AST 树 --> 小程序代码
编译时
劣势
- 运行时性能损耗低
- 指标代码明确,开发者所写即所得
- 运行时、编译时优化:比方框架会给予开发者更多的语法反对以及默认的性能优化解决,比方防止屡次 setData,或者长链表优化等等
劣势 -
语法限度高:须要齐全命中开发者在模板局部所用到的所有语法,语法受限,因为是 1:1 编译转换,开发者在开发的时候还是不得不去遵循小程序的开发标准,比方一个文件只能定义一个组件之类的
运行时
比起编译时,最大劣势是能够简直没有任何语法束缚的去实现代码编写
劣势:没有语法限度
微信小程序
文档必读
举荐将文档的指南、框架、组件、API、工具相干的通读一遍
根本内容
示例代码 github 地址:https://github.com/wechat-miniprogram/miniprogram-demo
根底
官网文档:https://developers.weixin.qq.com/miniprogram/dev/framework/
根底外围
graph
A[小程序冷启动] -- 启动 --> B[前台] -- 切后盾 --> C[后盾] -- 五秒后 --> D[挂起] -- 30 分钟后 --> E[小程序销毁]
C -- 切前台 --> B
D -- 切前台 --> B
-
更新机制
-
启动时同步更新
- 定期检查小程序版本
- 长时间未应用小程序
-
启动时异步更新
- 关上发现有新版本,异步下载,下次冷启动时加载新版本
-
开发者手动更新
- wx.getUpdateManager
-
-
代码注入
- 按需注入:“lazyCodeLoading”:“requiredComponents”配置门路进行打包
- 用时注入:在开启「按需注入」个性的前提下,指定一部分自定义组件不在小程序启动时注入,而是在真正渲染的时候才进行注入,应用占位组件在须要渲染但注入实现前展现
-
分包加载
-
准则
- 申明 subpackages 后,将俺 subpackages 配置门路进行打包,subpackages 配置门路外的目录将被打爆到 app(主包)中
- app(主包)也能够有本人的 pages(即最外层的 pages 字段)
- subpackage 的根目录不能是另外一个 subpackage 内的子目录
- tabBar 页面必须在 app(主包)内
-
独立分包
- 当小程序从一般的分包页面启动时,须要受限下载主包
- 独立分包运行时,App 并不一定被注册,因而 getApp()也不肯定能够取得 App 对象。根底库 2.2.4 版本开始 getApp 反对
[allowDefault]
参数,在 App 未定义时返回一个默认实现,当主包加载,App 被注册时,默认实现中定义的属性会被笼罩合并到真正的 App 中
-
-
调试小程序
- 应用 vconsole
- 开启 sourceMap 配置项
- 实时日志:重写 log,应用 wx.getRealtimeLogManager 封装,在经营后盾“开发 -> 开发治理 -> 运维核心 -> 实时日志 ” 查看
- errno:开发者本人抛出异样,针对 API 的 cb err 进行状态码的判断,针对业务场景语义化展现
如何兼容版本
版本号比拟
const version = wx.getSystemInfoSync().SKDVersion if (compareVersion(version, '1.1.0') >= 0) {wx.openBluetoothAdapter() } else { wx.showModal({ title: '提醒', content: '以后微信版本过低,无奈应用该性能,请降级到最新微信版本后重试' }) }
判断 API 是否存在
if (wx.openBluetoothAdapter) {wx.openBluetoothAdater() } else { wx.showModal({ title: '提醒', content: '以后微信版本过低,无奈应用该性能,请降级到最新微信版本后重试' }) }
wx.canIUse
判断以后环境是否能应用 api,和 jsdk 的 api 权限判断相似
wx.showModal({success: function(res) {if (wx.canIUse('showModal.success.cancel')) {console.log(res.cancel)
}
}
})
最低根底库版本
经营后盾设置最低根底库版本
框架
微信原生小程序框架官网文档
-
小程序配置
- 全局配置
- 页面配置
- sitemap 配置
-
框架接口
-
App:必须在 app.js 中调用且只能调用一次
- 一些全局的生命周期
- getApp:内部拜访 App 中数据的形式
-
-
页面
-
Page
- data
- 一些页面中的生命周期
- getCurrentPages:获取以后页面栈,能够获取以后页面信息,比方路由,也能够通过该办法实现跨页面赋值
// 跨页面赋值 let pages = getCurrentPages() // 以后页面栈 let prePage = pages[pages.length - 2] // 上一页面 prevPage.setData({// 间接给上一页面复制}) // 页面跳转后主动刷新 wx.switchTab({ url: '../index/index', success: function (e) {const page = getCurrentPages().pop(); // 以后页面 if (page == undefined || page == null) return; page.onLoad(); // 或者其余操作} })
-
-
Router
- 页面路由器有
switchTab
reLaunch
redirectTo
navigateTo
navigateBack
五个办法 - 与 wx 对象向同名的五个办法
switchTab
reLaunch
redirectTo
navigateTo
navigateBack
性能雷同;惟一的区别是,页面路由器中的办法调用时,相对路径永远绝对于this
指代的页面或自定义组件。
Page({wxNavAction: function () { wx.navigateTo({url: './new-page'}) }, routerNavAction: function () { this.pageRouter.navigateTo({url: './new-page'}) } })
自定义组件
- 页面路由器有
- Component:在微信开发工具右键新建组件主动创立了自定义组件模板,整体包裹在一个 Component 对象下
- Behavior:behaviors 是用于组件间代码共享的个性, 相似一些编程语言中的 ’mixin’ 或者 ’traits’,它能够将 behavior 模块的代码混入组件代码中,个别是抽离出逻辑代码和局部属性
// 官网示例
module.exports = Behavior({behaviors: [],
properties: {
myBehaviorProperty: {type: String}
},
data: {myBehaviorData: {}
},
attached: function(){},
methods: {myBehaviorMethod: function(){}}
})
根底用法,先新建一个组件,再通过组件自带的 behaviors 属性混入 behavior 模块,这个属性相似 vue 的 mixins
// 新建个组件
<view> 属性: {{myBehaviorProperty}} --- {{myCompProperty}}</view>
<view> 数据: {{myBehaviorData}} --- {{myCompData}}</view>
<view bind:tap="myBehaviorMethod"> 触发 behavior 的自定义办法 </view>
<view bind:tap="myCompMethod"> 触发组件的自定义办法 </view>
// 组件级 js
import testBehavior from './testBehavior'
Component({behaviors: [testBehavior],
properties: {
myCompProperty: {
type: String,
value: ''
}
},
data: {myCompData: 'myCompData'},
created: function (){console.log('[my-component]- created')
},
attached: function (){console.log('[my-component]- attached')
},
ready: function (){console.log('[my-component]- ready')
},
methods: {myCompMethod: function () {console.log('[my-component]- method')
}
}
})
// behavior.js
export default Behavior({behaviors: [],
properties: {
myBehaviorProperty: {
type: String,
value: 'myBehaviorProperty'
}
},
data: {myBehaviorData: 'myBehaviorData'},
created: function () {console.log('[my-behavior]- created')
},
attached: function () {console.log('[my-behavior]- attached')
},
ready: function () {console.log('[my-behavior]- ready')
},
methods: {myBehaviorMethod: function () {console.log('[my-behavior]- method')
}
}
})
面试会问到的
为什么要分包
目前小程序主包有限度大小不能超过 2M,整体 (包含分包) 不能超过 20M,对小程序分包能够优化首次启动的下载工夫,以及在多团队共同开发时能够更好的解耦
页面通信 — 组件高阶用法
-
跨页面赋值
- 相似 vue 中的 ref,间接操控组件的属性值
let pages = getCurrentPages() // 以后页面栈 let prePage = pages[pages.length - 2] // 上一页面 prevPage.setData({// 间接给上一页面复制})
- 应用 behavior 进行数据共享
-
应用
wx.nativgateTo
关上,这两个页面将建设一条数据通道,相似父子组件,能够通过emit
和on
相互发送- 被关上的页面能够通过
this.getOpenerEventChannel()
办法来获取一个EventChannel
对象 wx.navigateTo
的success
回调中也蕴含一个EventChannel
对象- 这两个
EventChannel
对象间能够应用emit
和on
办法相互发送、监听事件
seo 优化
小程序如何 seo 优化官网文档
- 被关上的页面能够通过
- 配置小程序 sitemap
- 小程序里跳转的页面 (url) 可被间接关上
- 页面跳转优先采纳 navigate 组件
-
必要的时候才申请用户进行受权、登录、绑定手机号登
- 开发中遇到过如果要通过企微群发公众号页面时,企微爬取不到页面信息,因为页面应用了静默受权,爬取页面的时候间接跳转到受权页了,所以获取不到页面信息
-
设置一个清晰的题目和页面缩略图
性能相干
- 小程序启动流程官网文档
- 小程序切换页面流程官网文档
-
如何晋升小程序性能
-
启动时性能优化
- 代码包体积优化(分包)
- 代码注入优化(懒加载模块)
- 首屏渲染优化
- 其余优化
-
运行时性能优化
- 正当应用 setState
- 渲染性能优化: 非必要不监听滚动事件,尽量少用简单动画成果
- 页面切换优化:防止在 onHide/onUnload 执行耗时操作,提前发动数据申请
- 资源加载优化:图片资源管制
-
内存优化:分包、按需注入,内存剖析,解决内存告警
- 内存透露:如果页面示例被挂载到全局或者其余中央还有应用到,那么该页面 this 得不到开释,容易造成内存透露,当须要其余页面用到该 this 时,在该页面 unload 时须要解决手动开释内存
如何进行埋点
-
- 手动设置本人的埋点零碎(须要埋点量少的时候)
- 如果是 vue、react 等框架则能够在 webpack 中加载本人写的 babel 插件,在转化 ast 这步主动插入埋点
- 小程序中能够用腾讯官网提供的埋点工具,也能够通过开发者工具自定义剖析设置埋点上报