序言几个月前,十分有幸参加微信小程序第一批内测. 但那时,远没有现在激动. 因为,那个时候并不曾意 ...
序言
几个月前,十分有幸参加微信小程序第一批内测. 但那时,远没有现在激动. 因为,那个时候并不曾意识到几个月后, 微信小程序将刷爆你的朋友圈。 21日深夜,微信官方放了一份关于”小程序”的内测邀请函,某公众号高调推送一篇文章,迅速引起朋友圈刷屏,很快便突破了10W+访问. 甚至有人连夜通宵写”小程序”开发教程. 这几日,内测的几个团队纷纷给出开发体验,于是我也把平日同事比较好奇的几点问题以及自己的看法和心得总结出来.
开发体验过程中,感觉到微信小程序应该算作一种 Hybird App,但并非像phoneGap一样视图完全依靠webview来显现,然后通过封装的 Javascript 与Native API通讯. 小程序的视图内, 即可以包括webview,也可以包括native view. 互相覆盖叠层展示. 相对来说,这种开发难度更大,但是实现起来比单纯的webview更加灵活. 同时对于H5中性能不足的地方,可以用Native实现. 对于用户体验来说是更接近原生了. 小程序的应用框架MINA完成了最难的部分,作为应用开发者的我们,只需要微信提供的wxml,wxss即可完成接近于H5的开发体验,完全不必去了解我所用的INPUT是 webview 的 INPUT 还是 Native 的 INPUT。接下来就一步一步带你走进小程序的世界。
MINA 这个名字就由来就好比MariaDB名字的由来。:0)
这是开发给到的架构图.
从图中可以看出,应用层和页面视图层之间的通讯是经由系统层的JSBridge实现的,页面单向接受来自应用逻辑层的数据流,应用逻辑层响应页面视图层的事件。页面视图层的每一个页面由wxss和wxml构成。而系统层JSBridage提供原生各种能力支持.
官方提供了开发者工具,虽然开发者工具和微信客户端实现的原理大不一样,但我们依然可以从这里去理解页面视图层和应用逻辑层.
开发者工具和我们平时Chrome调试一样,左边是页面,右边是控制台。但不同的是, 左边展示的页面和右边的代码似乎不是运行在同一个环境。因为平时调试时,我们在console输入document.body.outerHTML会打出页面HTML代码。在开发者工具中只会打印出appservice的页面内容。并非显示页面的内容。
同时刷新左侧区域,右边代码不会再次执行,除非点重启按钮。因此怀疑左侧页面和右侧控制台并非同一环境, 可以认为左侧页面就是架构图中的页面视图层,右侧控制台(除了wxml Tab外) 就是逻辑应用层。逻辑应用层想要更新页面就必须使用:
this.setData({text: 'update text'});
除此之外,别无它法。妄想通过DOM操作、Zepto、或者其它框架来更新页面是行不通的,因为在应用逻辑层无法直接获得页面视图层中的DOM节点。甚至在手机客户端上,完全没有window、document等全局对象。 开发者工具只是对整个架构的模拟,其中应用逻辑层应该还是运行在webview之上的,手机客户端的实现原理应该大不一样、应用逻辑层有可能完全不运行在webview上,这也就是为何手机客户端没有window、document等对象。
小程序实现数据绑定的方式如下:
<view>{{msg}}</view>
视图中以wxml语法添加一个节点,对于Vue或者是AngularJS用户是不是感觉颇为亲切和熟悉。唯一的区别就是没有v-text或者ng-bind的功能。
Page({
data: {
msg: 'Orginal msg'
},
onLoad: function () { this.setData({
msg: 'Updated msg'
});
}
});
更新数据时,对比三者的代码实现:
// 微信小程序this.setData({
msg: 'Updated msg'});// Vuethis.msg = 'Updated msg';// AngularJS$scope.msg = 'Updated msg';
接着我们加入另外一个INPUT
<input value="{{msg}}"></input>
对于INPUT,小程序并不存在类似 ng-model 或者是 v-model 的双向绑定指令,只能通过 value 进行设置. 当用户人工在INPUT中修改其中的值后,发现 view 中的值并不会跟着变, 这里与 Vue 和 AngularJS 表现不一致.
因为小程序是应用逻辑层到页面视图层的单向绑定,所以在应用逻辑层中不会感知到值的变化,而且也并不提供一个 getData 的方法去取到INPUT中的值,只能通过事件响应实现。而 Vue和 AngularJS 的双向绑定特性,人为在页面上的数据改变是可以直接反馈到逻辑代码里的。如果一定要实现类似功能,那就只有通过响应INPUT事件,实时更新view的数据. 我们再在 页面加个按钮:
<button bindtap="btnTap">Button</button>
逻辑层加入响应事件:
btnTap: function () { this.setData({
msg: 'Updated msg'
});
}
手动改变INPUT值为其它时,INPUT的值却并没有改回来。这里说明在 setData 操作时,应用逻辑层会先检测msg是否有变化,而此时应用逻辑层感知不到到人为修改的INPUT值,因此 setData 操作会被视为没有改变数据而不会去更新视图。所以官方提供另外一种方法强制更新视图:
this.setData({
msg: 'Updated msg',
}, {forceUpdate: true});
至于为何在 setData 时要检测数据是否变化过呢,而不是每次 setData 都去直接更新视图呢?我猜想是在应用逻辑层数据传递到页面视图层的这个过程,并非像暜通H5中dom.innerHTML = 'updated';一样简单,因此做这个检测也是起到对性能的一种保护作用吧。
再来看另外一种情况,非当前执行序列下更新数据。 修改btnTap事件如下:
btnTap: function () { var self = this; this.setData({
msg: 'Updated by button tap'
});
setTimeout(function () {
self.setData({
msg: 'Updated by setTimeout'
});
}, 3000);
}
但是结果并非像预期的那样三秒后改变文字。同理,此类情况如果是用AngularJS实现需要修改为:
setTimeout(function () {
$scope.msg = 'Update by setTimeout';
apply();
});
添加一行apply();或者用提供的$timeout方法。 而Vue即便在setTimeout中也可以不作改变,直接赋值。因为它的数据绑定是基于getter、setter的。 所以在MINA中也可通过类似方法实现:
setTimeout(function () {
self.setData({
msg: 'Updated by setTimeout'
});
self.update();
}, 3000);
所以看到这里,MINA在做数据绑定的时候和AngularJS的脏数据检查机制很像呢。
小程序提供了一系列网络请求API,支持 HTTP 请求、webSocket请求、以及上传下载文件。 但前提条件是在后台配置好了合法域名,只有合法域名的请求才被允许。
因为业务只涉及到 HTTP 请求, 所以这里只讨论由wx.request发起的 HTTP 请求。 官方规定最多只允许5个并发请求,并且暂时不提供定制的方法。
这个让我联想到了多数浏览器对单个域名最高并发数量设置为6个。与之不同的是:
浏览器的策略是针对单域名,但小程序中是针对所有请求(但因为合法域名只有一个,所以也就不存在多域名的问题)。 浏览器在单个域名请求超过6个时,只是会暂时阻塞后续请求,直至某个请求完成,但小程序似乎在多于5个请求并发时直接报错。
先忽略这个问题,那么,线上已经开发好了的接口是否可以直接使用呢?那就看以下几点:
小程序有新的AppId,如果以前接口是针对老的AppId开发的话,那肯定不适用。 自从 iOS9 推出 ATS 特性后,要求 App 内访问的网络必须使用 HTTPS 协议以保证网络链路安全,所以小程序也需要接口支持 HTTPS 协议。 客户端对于 HTTP 协议的一些特性不完全支持,比如 cookie。因此如果接口从 cookie读数据的,就需要修改为从参数读取。同理写 cookie 也需要修改为返回在 body 中,然后在逻辑层用 storge API模拟实现 cookie。另外还有一些比如返回 Content-type必须为 utf-8,否则客户端解析乱码等问题,都需要在接口改造时注意。 出于安全考虑,部分 header 用户是无法自行定义的,如果接口中存在 Referer 校验等类似问题的话可能要重新修改校验规则。 请求由客户端发出,因此为方便跨域的 jsonp 请求就没有存在的必要。
综上所述,在请求后端接口上大体还是和以前体验差不多的。
客户端请求是由客户端发起的比较好理解,因为之前就判断客户端的应用逻辑层代码不是运行在webview上。小程序开发者工具的应用逻辑层代码应该是运行在webview上的,那么它的 http 请求是由 node 发起的还是 webview 发起的呢? 出于好奇研究了一下,发现 wx.request 在开发者工具中是由 webview 发起的 xhr 请求:
既然是 webview 发起的 xhr 那么肯定就会受到浏览器跨域安全策略的限制。
分别在普通浏览器和小程序开发者工具的 console 中注入 jQuery 后执行:
$.get('http://www.qq.com');
可以发现普通浏览器会在xhr.send()时报错,但开发者工具不会,而且能正常返回结果。
普通浏览器:
小程序开发者工具:
由此可见,开发者工具使用了一些手段屏蔽或者绕过了 webview 的跨域安全策略。
以上体验都是在手机充值小程序的开发过程中的心得与体会,希望能通过梳理的几点问题能够大致了解到小程序的工作方式。因为我们的业务比较简单,使用到的技术可能只是MINA中的冰山一角,所以本文涉及的内容有一定的局限性,后续新的心得与体会也会在这里补充,更新。
从8月初开发小程序到现在,起初每天工作超过15个小时,从刚开始一步一个坑,框架改了又改到现在框架基本稳定,开公内测。这一切都离不开WX GG们的辛苦努力,这帮天才GG们卖得一手好萌,写得一手好代码,更重要的是他们精力充沛,无时无刻都在帮我们定位问题,解决问题。付出的努力是值得的,从现在小程序的轰动趋势来看,小程序注定要创建一个***。
最后,手机充值小程序井然有序的在进行着一步一步的迭代,这个过程更加顺畅得心应手,感谢手机充值团队的产品、后台、视觉、重构等同学付出的努力,希望大家多多支持手机充值,也希望在小程序上线之日,手机充值小程序能以最优雅的姿态与大家见面。