什么是小程序

小程序页面实质上是网页,应用了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

小程序类型利用的技术选型

渲染页面的技术计划

  1. 用纯客户端原生技术渲染
  2. 用纯web技术渲染
  3. 用客户端原生技术与web技术联合的混合开发(hybrid)渲染

    计划比照

  4. 开发门槛:web门槛低,原生也有像RN这样的框架反对
  5. 体验:原生体验比web好太多,hybrid在肯定水平上比web靠近原生体验
  6. 版本更新:web反对在线更新,如果小程序用原生开发,则须要打包到微信一起审核
  7. 管控与平安:web可跳转或是扭转页面内容,存在一些不可控因素和平安危险

    计划确定

  8. [x] 小程序的宿主环境是微信等手机app,用纯客户端原生技术来编写小程序,那么小程序代码每次都须要与手机app代码一起发版。所以该计划不可取
  9. [x] web反对有一份正本资源包放在云端,通过下载到本地,动静执行后即可渲染出界面,但纯web技术在一些简单的交互上可能有性能问题。所以该计划不可取

    • 在web技术中,UI渲染跟脚本执行都在一个单线程中执行,这就容易导致一些逻辑工作抢占UI渲染的资源
  10. [ ] 两者联合的hybrid技术来渲染小程序,用一种近似web的形式来开发,并且能够实现在线更新代码

    • 扩大web的能力,比方输入框组件(input、textarea)有更好的管制键盘的能力
    • 体验更好,同时加重webview的渲染工作
    • 用客户端原生渲染内置一些简单组件能够提供更好的性能

双线程模型

小程序的渲染层和逻辑层分为两个线程治理

  • 视图层(Web View) -> WebView进行渲染

    • 界面渲染相干的工作都在WebView线程里执行,通过逻辑层代码区管制渲染哪些界面。一个小程序存在多个界面,所以视图层存在多个WebView线程
  • 逻辑层(App Service) -> JsCore线程运行js脚本

    • 创立爱你一个独自的线程去执行js代码,在这里执行的都是无关小程序业务逻辑的代码,负责逻辑解决、数据申请、接口调用等
  • JSBridge:下层开发与Native(零碎层)的桥梁,使小程序可通过API应用原生的性能,且局部组件为原生组件实线,从而有良好体验
    设计目标:为了管控和平安等问题,阻止开发者应用一些,例如浏览器的window对象,跳转页面,操作DOM、动静执行脚本的开放性接口
应用沙箱环境提供纯javascript的解释执行环境
  1. 客户端零碎,在pc运行时用javascript引擎执行js代码
  2. ios:在ios零碎时应用ios提供的Js core框架执行js代码
  3. 安卓:在安卓零碎时应用腾讯的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/

根底外围

graphA[小程序冷启动] -- 启动 --> B[前台] -- 切后盾 --> C[后盾] -- 五秒后 --> D[挂起] --  30分钟后 --> E[小程序销毁]C -- 切前台 --> BD -- 切前台 --> 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().SKDVersionif (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>// 组件级jsimport 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.jsexport 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关上,这两个页面将建设一条数据通道,相似父子组件,能够通过emiton相互发送

    • 被关上的页面能够通过this.getOpenerEventChannel()办法来获取一个EventChannel对象
    • wx.navigateTosuccess回调中也蕴含一个EventChannel对象
    • 这两个EventChannel对象间能够应用emiton办法相互发送、监听事件

    seo优化

    小程序如何seo优化官网文档

  • 配置小程序sitemap
  • 小程序里跳转的页面(url)可被间接关上
  • 页面跳转优先采纳navigate组件
  • 必要的时候才申请用户进行受权、登录、绑定手机号登

    • 开发中遇到过如果要通过企微群发公众号页面时,企微爬取不到页面信息,因为页面应用了静默受权,爬取页面的时候间接跳转到受权页了,所以获取不到页面信息
  • 设置一个清晰的题目和页面缩略图

    性能相干

  • 小程序启动流程官网文档
  • 小程序切换页面流程官网文档
  • 如何晋升小程序性能

    • 启动时性能优化

      • 代码包体积优化(分包)
      • 代码注入优化(懒加载模块)
      • 首屏渲染优化
      • 其余优化
    • 运行时性能优化

      • 正当应用setState
      • 渲染性能优化:非必要不监听滚动事件,尽量少用简单动画成果
      • 页面切换优化:防止在onHide/onUnload执行耗时操作,提前发动数据申请
      • 资源加载优化:图片资源管制
      • 内存优化:分包、按需注入,内存剖析,解决内存告警

        • 内存透露:如果页面示例被挂载到全局或者其余中央还有应用到,那么该页面this得不到开释,容易造成内存透露,当须要其余页面用到该this时,在该页面unload时须要解决手动开释内存

    如何进行埋点

  • 手动设置本人的埋点零碎(须要埋点量少的时候)
  • 如果是vue、react等框架则能够在webpack中加载本人写的babel插件,在转化ast这步主动插入埋点
  • 小程序中能够用腾讯官网提供的埋点工具,也能够通过开发者工具自定义剖析设置埋点上报