这是我参与「第四届青训营 」笔记创作活动的的第17天
课程目标
- 认识和了解小程序的业务产品价值
- 学习和掌握小程序相关技术原理
小程序最大的价值就是产品价值,它构建了一个更加完整的生态也扩充的更多的业务场景,这是小程序最最最重要的价值。
发展历程
- 2017、2018年是小程序发展初期,这个阶段最早由微信开始探索;因为是微信出品,所以小程序还未发布就已经有了很高的关注度。
- 17年1月份小程序正式发布,但这时候还没有完全对个人开发者开放,主要针对企业开放,直到3月份,小程序正式面向个人开发者开放,自此,小程序数量进入爆发期。
- 17年4月份,小程序码的新型图形码的到来,实现线下场景和线上小程序的沟通串联。
- 17年9月份,支付宝小程序也开始了公测,标志着各大厂进入小程序领域开始竞争,围绕小程序构建和丰富独属于自己的生态。
- 17年12月份轻度小游戏上线(跳一跳)。
- 18年1月份,因为小程序可以打开 app ,这也标志着小程序可以为其它 app 引流的功能开放。
- 18年各大厂相继上线自己的小程序,加速布局小程序生态。
- 19年小程序被列入腾讯的战略,微信也丰富了小程序的入口以此来开放更多的流量。
- 19年9月份,微信贴片广告标志着小程序正式开始商业化建设(业务最终都是为了赚钱),随着小程序越来越复杂,小程序4M 的限制无法满足需求。
- 19年11月份,小程序开发包总包上限12M ,让开发者可以构建更加复杂的小程序应用。
- 2020年疫情的出现加速各种小程序的出现,同时也为小程序赋予了直播和小商店等更多的属性,为小程序的商业化带来更多的可行性。
- 越来越多的场景出现导致小程序整体也逐渐发展的越来越成熟。
核心数据
这是2020年底的数据,可以看出小程序的数量特别的庞大。
小程序生态
小程序是超级 app 发展到一个阶段的必然产物,因为这些超级 app 想要构建更多的场景,让更多人用只靠自己开发的程序是永远做不完的,所以需要开放出来给其他开发者做,小程序目前的生态也基本上是围绕各大超级 app 来的。
业务价值
与 web 区别
为了平台管控:
- 有着固定的语法以及统一的版本管理,平台可以更方便的进行审核。
- 平台能够控制各个入口,例如:二维码、文章内嵌、端内分享。入口上也能带来更好的用户体验。
- 小程序基于特殊的架构,在流畅度上比 web 更好,有更优秀的跳转体验。
三大价值
- 渠道价值。由于小程序的便捷性,依托于超级平台,小程序能够充分为很多场景导流,如美团和美团优选微信小程序带来的流量分别是40%和80%。
- 业务探索价值。相比原生 APP 来说,小程序的开发难度和成本都降低的很多,这就创造了很多场景开发者能够用小程序来快速试错,不断探索新的业务价值。
- 数字升级价值。线下到线上如何做?从轻消费类的快餐、茶饮到地产汽车等大宗消费,小程序都展示了良好的容错空间。线下场景的小程序覆盖范围广。
技术解析
小程序原理
怎么样让第三方开发应用最简单最方便?
使用 webview 和 JSBridege 技术来开发。 webview 可以简单理解为 app 内置的浏览器,可以在 app 内浏览网页,但是除了 web 本身,想让开发者能够通过 JS 调用更多 app 上的功能怎么办?例如:打开相机、地图等,单靠 web api 是做不到的,这时候就需要 JSBridege , JSBridege 是 js 和 native 代码之间的桥梁,能让两者相互沟通相互调用,实现 JSBridege 的方式有很多,例如:代码注入、 url 拦截等。
这种方式的问题?
- 无网络的情况体验不佳
- 解决:资源离线化。把整个资源下载到 app 上,网页求换也可以通过这种方式解决。
- 网页切换体验不佳(不管怎样, web 都要从远程加载资源)
- 如何管控保证安全
- 对外开放平台先不说功能十分齐全,最重要的一点就是保证平台的安全,因为你永远无法杜绝有人恶意在你的平台上作恶。
- 如果由人来审核,那么我们要把所有的网络链接都管控起来,经过审核的链接才可以在平台打开,先不考虑数量的问题,网页的动态性就无法解决。
例如:审核是在2022-02-02之前完成的,然后到2022-02-02当天网页就变了。
if(Date.now() > new Date('2022-02-02')) { document.body.innerHTML = '<h1>hello world</h1>' }
小程序设计目标:
- 开发门槛低
- 大部分开发者都会且很容易学习的技术(HTML + CSS + JavaScript)。
- 接近原生的使用体验
- 三个问题:资源加载 + 渲染 + 页面切换
- 资源加载可以用资源离线化解决
- 渲染:独立 JS 沙箱。
- 页面切换可以每次切换页面时保留之前的页面,降低成本。
- 能够保证安全可控
- 需要解决 web 灵活性问题, web 灵活是因为它可以用 js 来操作 DOM ,通过 js 来改界面。
- 独立 JS 沙箱(把 DOM 的 api 都禁用掉,不允许使用。开发者没办法直接操作 DOM ,只能做一些 js 的逻辑)
不操作 DOM ,如何控制页面的渲染?
只需要关心数据流而不需要具体操作 DOM 就可以根据数据来渲染页面。
小程序整体的架构:
在浏览器中,当 JS 操作频繁时动画会卡顿,因为它们是运行在同一进程中。这种结构将 JS 和渲染分离顺带解决了这个问题。
这样的通信结构决定了小程序的性能问题在数据传递。
小程序语法
以字节小程序为例:
<view tt:for="{{list}}" tt:if="{{isOpen}}" bindtap="onTap"/>
Page({
data: {
list: ["a", "b", "c"],
isOpen: true
},
onTap: function() {
console.log('tap me!')
}
})
用 Page 对象包裹整个页面。
view {
background-color: "red";
width: 750rpx;
}
rpx (CSS 内没有)适配单位, iPhone6 写像素的话是375px ,小程序是把它划为了750rpx。
实现番茄时钟(倒计时)
<view class="container">
<view class="clock">{{ timeText }}</view>
<button tt:if="{{ running }}" class="button" bindtap="onReset">重置</button>
<button tt:else class="button" bindtap="onStart">开始</button>
</view>
const DEFAULT_TIME = 25 * 60;
function formatTime(time) {
const minutes = Math.floor(time / 60);
const seconds = time % 60;
const mText = `0${minutes}`.slice(-2);
const sText = `0${seconds}`.slice(-2);
return `${mText} : ${sText}`
}
Page({
data: {
timeText: formatTime(DEFAULT_TIME),
running: false
},
setTimer: function() {
this.timer = setInterval(() => {
this.time = this.time - 1;
if(this.time < 0) {
clearInterval(this.timer);
return;
}
this.setData({
timeText: formatTime(this.time)
})
}, 1000)
},
onStart: function() {
if(!this.timer) {
this.time = DEFAULT_TIME;
this.setTimer();
this.setData({
running: true
})
}
},
onReset: function() {
clearInterval(this.timer);
this.timer = null;
this.setData({
timeText: formatTime(this.time),
running: false
})
}
})
相关拓展
目前的小程序跨端框架主要为了解决两个问题:
- 复杂应用构建。
- 一次开发可以跨多端。
跨端框架介绍
跨端框架原理
不论什么框架都逃不开这两种实现方式:
- 编译时:JS 代码编译的时候转小程序的语法
- 运行时:代码实际在客户端运行的时候来适配小程序的语法
编译时
先提一下 AST 语法树:
Vue 当中的一段语法:<View>{foo ? <View /> : <Text />}</View>
对应小程序的语法:
<view><block tt:if={foo}><view /></block><block tt:else><text /></block></view>
缺陷:
- 无法完全抹平差异
- 不论是 React 和 Vue 等各种框架,它们的用法都十分多样,而且会不断添加新的特性而小程序本身有很多的限制,在转换过程中,很多特性没有办法转换,所以就要在用框架写代码时加很多的限制,违背了初衷,现在更多的方案是采用运行时的方式。
运行时
实现主要依赖这两个部分:
- 虚拟 DOM
- template 组件
虚拟 DOM 本质上是 JS 中的一个对象,可以通过虚拟 DOM 来生成实际的 DOM 。
template 组件能帮助我们动态的生成模板。
运行时的结构:
实际运行时, React 和 Vue 等框架运行在逻辑层,当它们想实际操作 DOM 时,把实际 DOM 换成虚拟 DOM ,运行完生成完虚拟 DOM 树后,把整个虚拟 DOM 树传递给渲染层,渲染层根据虚拟 DOM 的结构组合 template 生成实际要渲染的 DOM 树,小程序再根据实际的模板来创建页面。
setData 传数据多了是一个性能瓶颈,所以在实际实现的时候,这些框架也做了些优化,尽可能的减少 serData 数据传递。例如:逻辑层不必每次传整个虚拟 DOM ,只传 新增/修改/删除 的部分;长列表渲染的话,生成的 DOM 树可能很大,有的框架会做出虚拟列表,只展示能在实际页面中看得到的列表项,其余列表项能滚动到时再来渲染。
缺陷:
- 在一些场景下相比小程序原生语法性能会更差
- 数据量会比小程序原生语法大