正版微信小程序开发之一:语言,生命周期与数据渲染

小程序上线至今已有1年多时间了,我跟大家一样,目睹了小程序生态的演进,和API的变化。时下,打开某度搜索小程序开发,可谓是海量结果,然而真正理解了小程序,有质量的开发教程可谓“凤毛麟角”。我在这个开篇里想跟大家先探讨一下小程序的运行原理,做到知己知彼,再对症下药,用比较正确的开发姿势和工具去开发小程序。

语言与渲染环境

小程序的开发语言是JavaScript(不知道的请举手),小程序早期Runtime并不支持ES5+的语法,现在你可以看到的较新版本的DevTools里有个“ES6转ES5”,这个内置的预处理极大的方便了编码,tips:小程序ES6代码转译也是用的Babel,对API的支持情况可以看看这篇文档https://developers.weixin.qq.com/miniprogram/dev/devtools/details.html#客户端es6-api-支持情况

在这里照顾一下新同学,简单说说关于Javascript和ES的概念,老同学请略过这一段。

准确地说,ES(ECMAScript)并不是什么语言级别的东西,它的Level可比语言要高,一般称为“Specification(规范)”。JavaScript只是对这个规范的具体实现和扩展,玩过AdobeFlash的同学(暴露年龄~~),肯定知道ActionScript,它也是ECMAScript的实现。世上本没有ES5,只是因为有了ES6(版本号:ES-2015),然后是ES7(ES-2016)。

那么这些ESx有什么样差异呢?这得分阶段来看了:

在ES2015规范问世后相当长的一段时间内,大概是JavascriptCore/V8等这些解释器还没准备好拥抱它,在这段时间里,需要把新的语法转换成旧的写法,解释器才能正确的解释执行。因此就出现了Babel这样的转译器以及各种Polyfill模块;后来,Mozilla/Google/Apple这些大厂开始升级解释器,陆续内建地支持ES新语法。(不能再写这个了,不然我得把文章标题改为JavaScript的前世今生啦~~)

回到微信小程序里来,就语言环境来说,有三种:

  • iOS:JavaScriptCore/JsCore
  • Android:X5,基于webkit(WebCore + JsCore)
  • 开发工具:nwjs(原名是node-webkit),基于 Chromium和 Node.js运行

总体上说来,这三个语言环境没什么太大的差异,无非是各自的各个版本对ES语法及新特性的支持情况有稍许不同。对开发来说,无需过多关心这个,打包上传时“ES6转ES5”就OK啦,有坑再填。

生命周期

小程序管理生命周期的对象有三个,App,Page和Component,其中Page和Component都属于UI层面。每个对象都有自己的生命周期,并且这些对象的生命周期函数在运行时也是穿插在一起的,因此不能孤立地看待不同对象的生命周期。

我们先来看看这三个对象的具体情况:

App生命周期

App lifecycle

App只会初始化一次,也就是说 app.onLaunch 回调只会call一次,紧接着就call app.onShow,进入本次启动后要显示的Page的生命周期。

当退出小程序时,call 当前页面的 page.onHide,最后调用 app.onHide,show和hide循环往复。

Page生命周期

Page lifecycle

当页面被请求时,页面初始化(包括内部引用组件的创建),然后调用 page.onLoad,页面加载完毕后, page.onShow

当离开页面时,有两种情况:

  • 如果页面出栈(如:导航的redirect/reLaunch),则调用 page.onUnload

  • 如果页面不出栈(如:导航的navigate),则调用page.onHide

Component生命周期

Component生命周期

组件从创建到渲染前,依次调用 component.createdcomponent.attached 回调,渲染树创建完成后,开始首次渲染,调用 component.ready 回调。

当组件节点在DOM Tree上移动后,调用 component.moved;

当组件被卸载(通常是条件渲染或者Page被卸载)时,调用 component.detached,组件的生命周期结束。

App与Page的生命周期关系

App与Page的生命周期关系

当App完成启动阶段后,开始进入本次启动的首个页面的生命周期,依次调用 page.onLoadpage.onShow

当App退出(切到后台)时,会先调用当前显示页面的 page.onHide,然后调用 app.onHide

当App唤醒(切回前台)时,会依次调用 app.onShow 和 本次启动的首个页面的 page.onShow

Page与Component的生命周期关系

Page与Component的生命周期关系

)

小程序组件在引用页面初始化时创建(未渲染),依次调用 createdattached,当所有关联组件节点被加入DOM Tree时,引用页面上触发 page.onLoad。同时,组件节点开始进行渲染树合并,主要是混入CSSTree。

当组件节点首次渲染完成后,组件内调用 ready

当全部关联组件 ready 后,引用页面上触发 page.onReady

视图/数据渲染

在讲渲染前,先来看一下大家耳熟能详的两种模式(早期靠手的时代这里就略过不说了):双向绑定和单向数据流。

双向绑定

通过代码逻辑,把Model和View binding在一起,更新Model时,View就会自动更新,反过来,如果更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。

典型框架:Vue。

单向数据流(单向绑定)

单向数据流模式主要是加入了一个Store做状态管理,View上触发动作,动作改变Store,Store变化引起View更新(单向数据绑定)。

典型框架:React。

我们这里重点不是去讨论单向和双向的问题,因此不做更多展开描述,主要来看看小程序的数据渲染方式。

微信小程序使用的是单向绑定,有经验的同学可能从 setData 这个函数就猜想出来了。一起来一段简单的例子:

// page.js
Page({
  onLoad(){
     wx.request({
       url: 'https://api.server.com/data',
       success: this.setData.bind(this)
     })
  }
})
<block wx:if="{{data.sample}}">
  <view>{{data.sample}}</view>
</block>

<block wx:else>
LOADING...
</block>

上面这个简单的例子中,一开始page会显示“LOADING...”,当HTTP请求完成后,页面会显示API服务器响应的数据。

这就是小程序数据渲染的大致过程了。

setData之后?

setData之后,到view被更新之前,发生了什么样的细节呢?欢迎在留言区表达你的看法。

公众号 前栈笔记

推荐阅读更多精彩内容