小程序高级电商前端第1周走进Web全栈工程师<二>
业务对象的重要性:
在上一次https://www.cnblogs.com/webor2006/p/13128911.html已经实现了对于首页顶部主题数据处理,不过目前看一下咱们请求的代码:
这里就得啰嗦一下关于小程序代码层级的问题了,属于思想层面的,往往这些才是最让自己能够成长的东西,本身写业务代码并不是一个很困难的事,所以这种啰嗦是很有必要的,由于js是一种动态语言,它本身是没有类型约束的,所以如果不给它分层那随着业务的编写这里面的代码就会变得非常之臃肿不好维护,那回到咱们目前这个js文件:
很明显它是一种页面级别的js,而它里面的职责主要是用来控制数据绑定,也就是类似于MVC中的C层,它是View层和M业务逻辑层的一个桥梁,不应该负责具体的业务逻辑的,所以这里分出一个M层了来,新建一个目录:
好,接下来则需要来新建一个业务的js文件,那么接下来又得啰嗦一下了,这个业务js的文件名取名成啥呢?这里的业务叫网络么?很显然网络不可能是一个业务对象,这里业务对象应该是主题,因为请求的就是主题的数据嘛,所以咱们这样取名:
这里一定要重视业务对象的寻找,它对于一个复杂的商用项目是很重要的,接下来咱们则来定义一个业务方法:
但是!!!这个命名也是有问题的。。好吧,一个这么简单的东东引出这么多“思想”问题,值得么?当然是值得的,扣得越细你的提升则越多, 你看一下这个方法名很明显是获取顶部的主题,貌似没啥毛病呀,在首页不就是顶部么?
嗯,确实是,但是!!还会有很多其它的Theme,那你咋命令呢?由于它是一个sale的主题,那这样改呗:
也就是名字中增加了业务字段,很明显也不太好,因为这块位置未来是动态可以配置的,有可能还可以配优惠券之类的,所以这里建议是像这种不要以业务来给它命名,可以给它们定义一些编号,像这样:
嗯,不过更加好的命令应该再加一个单词:
因为有可能其它页面也需要Theme,加一个页面则会更加的清晰。
封装HTTP请求:
接下来咱们则把网络请求的代码剪切到这个业务方法中来:
嗯,貌似很完美,但是很明显这块代码有问题:
那怎么解决呢,用回调,如下:
import {config} from "../config/config"; class Theme { static getHomeLocationA(callback) { wx.request({ url: `${config.apiBaseUrl}theme/by/names`, method: 'GET', data: { names: 't-1' }, header: { Authorization: config.appKey }, success: res => { callback(res.data) } }) } }
此时在我们的home.js的生命周期中就可以这样来调用了,当然啦先要将咱们新建的js导出一下:
调用:
编译运行其界面显示一切正常,那就完美了么?其实不然,虽说现在home.js中代码清爽了,但是!!对于业务网络请求每次还是写起来比较麻烦,所以有必要对网络请求进行一个二次封装,以应对未来若干个大量的业务的网络请求的应用效率:
对于网络请求应该算是一个工具类,所以咱们封装成一个工具方法,在我们新建小程序工程时默认IDE为我们生成了一个工具文件:
const formatTime = date => { const year = date.getFullYear() const month = date.getMonth() + 1 const day = date.getDate() const hour = date.getHours() const minute = date.getMinutes() const second = date.getSeconds() return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') } const formatNumber = n => { n = n.toString() return n[1] ? n : '0' + n } module.exports = { formatTime: formatTime }
这里删除它,对我们没啥用,新建一个咱们自己的:
具体的代码比较简单,直接贴代码了:
import {config} from "../config/config"; class Http { static request(url, data, method = 'GET', callback) { wx.request({ url: `${config.apiBaseUrl}${url}`, method, data, header: { Authorization: config.appKey }, success: res => { callback(res.data) } }) } } export { Http }
接下来回到咱们的业务方法中,调用就比较简单了:
不过这里有个细节还得优化一下,对于方法参数的传递其实用这种对象的方式语义会更加的清晰:
而我们目前是直接传递的:
所以改造一下,比较简单:
此时咱们就可以用对象的方式来传递参数了:
import {Http} from "../utils/http"; class Theme { static getHomeLocationA(callback) { Http.request({ url: `theme/by/names`, data: { names: 't-1' }, callback: data => { callback(data) } }) } } export { Theme }
其实像Flutter中的命名参数也是类似的写法,此时咱们的调用又更加简单了,编译运行界面一切正常。
小程序中使用async和await的难点分析:
对于上面的封装已经“接近”完美了,为啥说“接近”呢? 因为还有不完美的地方嘛,有两层回调,代码显得比较乱:
其造成有两层回调的根据原因在于请求网络是一个异步处理,而在JS中处理异步有三种方式:
- callback
这个是最常用的,但是如今用得较少了,因为代码看着比较乱。 - promise
这个比callback要强,没有第三种好,但是!!它是第三中的一个必备的条件。 - async await
这种也是如今比较推崇的写法了,像Koltin、Flutter都有这样的写法,要能这样写的前提必须我们要调用的功能上返回的是promise才可以。
那咱们要用async await那直接用就成了呗,先在要执行异步的调用前面加上await:
报红了是因为如果一个函数内部出现了await,则需要在函数声明上加上async,如下:
但是!!!目前微信的wx.request是不会返回promise的,注意:并非只有返回promise的函数前面才能加await,其实函数返回普通的值也能加,但是加了await是没啥意义的,只有在promise前加await才有意义, 那。。说了这么多居然用不了async await,那不是浪费表情么?当然能用,经过一定的包装能让它转换成带promise的函数,下面就来看一下如何来转换。
使用LinUI Promisic让小程序内置API支持Promise:
这里则开始对wx.request进行一下包装达到能返回promise,进而可以使用async和await,那怎么弄呢?其实这里需要用到大神开源的LinUI组件既可解决,可以参考http://doc.mini.talelin.com/function/,在它网页前言也描述了使用的背景:
在这里先不用LinUI组件,这是开源的一个库,需要进行安装,为了学习的连贯性暂且先不安装,其实也就是一个函数,直接先拷到工程中来使用既可,如下:
const promisic = function (func) { return function (params = {}) { return new Promise((resolve, reject) => { const args = Object.assign(params, { success: (res) => { resolve(res); }, fail: (error) => { reject(error); } }); func(args); }); }; }; export { promisic }
其中很明显看到参数就是一个函数,然后最终返回的是一个Promise:
具体的转换细节暂且先不过多纠结,先用起来,怎么用呢,其实很简单:
此时就可以将回调给去掉了,因为咱们调用这个函数时就跟同步方法一样了,不需要通过回调来拿结果了:
将回调函数全部替换为async和await:
接下来则可以将theme.js中的回调也改为async和await了,改法一样:
接下来home.js中也得改写一下了:
接下来则编译看一下有木有问题:
报错了。。这是因为async await是ES7的语法,而小程序现在是只支持ES6,要想支持ES7,则需要设置一下:
此时再编译就木有报错了,但是!!!图片出不来了:
这是为啥呢?从网络请求中貌似数据也正常请求下来了:
这里将结果打出来瞅一下:
编译:
所以咱们修改一下网络请求返回的结果:
这样对于整个HTTP的请求的封装就比较完美了。
更正:
最后再来做一个更正说明,其实在上一篇也说明过了https://www.cnblogs.com/webor2006/p/13128911.html,这里再来说一下,因为不说明上面所写的无法正常在本地显示的:
同样这篇也是去年写的,所以。。