全栈之路-杂篇-前端代码封装
在项目开发过程中,代码的封装是很有必要的,我觉得这是程序员进阶的一个重要的技能,不会封装代码,你的代码看起来乱的一批,基本上不能维护,像一次性塑料袋一样,用完一次就失去了价值,这同时也会无缘无故的增加项目的总体的代码量,重复代码的不断叠加,谁也是这么一步一步走过来的,但是我要学着去改变,主要是学习这其中的思想,从一个简单的http请求的处理来看看如何进行代码的封装,让你的代码优雅。
一、烂透了的代码
简单说一下,这个场景是什么,就是从服务器请求接口,将数据展示到页面上,很简单,也是最常用的,最基础的功能,先看看一段最烂的代码,不是说有多烂,只是说实现了功能,其他的地方一无是处的,哈哈,下面是微信提供的请求数据的API
1 wx.request({ 2 url: '接口的地址url', 3 data: { 4 names:'t-1' 5 }, 6 method: 'GET', 7 header: { 8 appkey:'your appkey' 9 }, 10 success: res=>{ 11 this.setData({ 12 topTheme:res.data[0] 13 }) 14 } 15 }) 16
我写了挺长时间的代码了,我发现一直以来,都是这么写的,没有什么封装,擦!这段代码本身没有问题,功能也实现了,但是让人看起来很不爽,后期的维护很费劲,而且随着项目的开发进行,没有用处的垃圾代码会直线上升,这其实是可以优化的,看看有哪些地方是可以进行优化的?
二、不是那么烂了
优化可以试着从下面几点入手:
1、常量配置化
像url地址、appkey这种是通用的,最起码url的域名是通用的,可以写到一个单独的配置文件中,这样的话,很好维护,就像这样子:
1 const config = { 2 appkey:'your appkey', 3 apiBaseUrl:'通用的url地址' 4 } 5 // ES6的语法导出 6 export { 7 config 8 } 9 10 // 顺便说一下,其他的js文件如何导入呢? 11 import { 12 config 13 } from "文件的位置。。。";
2、业务处理的封装
这个一般会放在单独抽象出来的model层中,也就是项目中的model文件下的js文件中,我们将拆分出来的模块都抽象成一个个的js文件,具体的处理逻辑我们在这里处理,具体操作是在根目录下面新建model文件夹,在model文件夹下新建theme.js文件,代码具体如下:
1 import { 2 config 3 }from '文件位置。。。' 4 5 // 关于主题的相关的业务的处理 6 class Theme { 7 // 获取localhostA位置的主题 8 static getHomeLocationA(callback){ 9 wx.request({ 10 url: `${config.apiBaseUrl}theme/by/names`, 11 method: 'GET', 12 header: { 13 appkey: `${config.appkey}` 14 }, 15 data: { 16 names: 't-1' 17 }, 18 success: res => { 19 callback(res.data) 20 } 21 }) 22 } 23 } 24 // 别忘了导出 25 export { 26 Theme 27 }
在page中我们就能这样引用Theme类中的方法了:
1 Theme.getHomeLocationA(data =>{ 2 this.setData({ 3 themeA:data[0] 4 }) 5 })
看起来并没有简化,反而多增加了一个文件,哈哈,这么想也没什么问题,不反驳,但是优化之路还在继续,这还远远不够呢!
三、代码看起来整洁多了
在第二部分的基础上,我们进一步封装代码,将wx.request()进一步封装成一个通用的工具类,进一步优化这个代码!
1、封装微信小程序的原生API
我们在utils文件夹中新建http.js文件来做wx.request()的封装,具体代码如下:
1 // wx.request的封装 2 import { 3 config 4 }from '文件位置。。。' 5 6 class Http{ 7 static request({url,data,callback,method='GET'}){ 8 wx.request({ 9 url: `${config.apiBaseUrl}${url}`, 10 method: method, 11 data: data, 12 header: { 13 appkey: `${config.appkey}` 14 }, 15 success: res => { 16 callback(res.data) 17 } 18 }) 19 } 20 } 21 // 别忘了导出 22 export { 23 Http 24 }
2、model层的调用
model层需要进行简化,至于page页面层,不用做修改
1 class Theme { 2 // 获取localhostA位置的主题 3 static getHomeLocationA(func){ 4 Http.request({ 5 url:'theme/by/names', 6 data:{ 7 names:'t-1' 8 }, 9 callback:res=>{ 10 func(res) 11 } 12 }) 13 } 14 }
这个对异步请求的处理使用callback进行回调的用法基本上就封装完成了,但是你要说这是终极解决方案,那肯定不是,如何处理这个异步回调请求,还是需要优化的,终极解决方案是利用ES6中async和await,这个的本质还是利用Promise对象进行异步请求回调的处理
四、代码有点优雅
代码封装的终极解决方案,虽然用了一段创造性的封装小程序原生API,可惜不是我创造的,七月老师写的一段简短的,很有技巧性的代码,如何利用async和await实现异步请求处理,看看代码的实现:
1、继续封装小程序API
1 class Http { 2 static async request({ 3 url, 4 data, 5 method = 'GET' 6 }) { 7 // 这里的关键是promisc方法,将原生API转换成Promise对象 8 const res = await promisic(wx.request)({ 9 url: `${config.apiBaseUrl}${url}`, 10 method: method, 11 data: data, 12 header: { 13 appkey: `${config.appkey}` 14 } 15 }) 16 return res.data 17 } 18 }
2、model层调用Http类封装的request方法
1 // 获取localhostA位置的主题 2 static async getHomeLocationA(){ 3 return await Http.request({ 4 url:'theme/by/names', 5 data:{ 6 names:'t-1' 7 } 8 }) 9 }
3、page层调用model层getHomeLocationA方法
1 onLoad: async function(options) { 2 // 其实只有这一行的代码,至于其他代码跟这次封装没关系了,一定要async和await一起使用 3 const data = await Theme.getHomeLocationA() 4 this.setData({ 5 themeA:data[0] 6 }) 7 },
你觉得可能一次请求中代码量并没有少,反而层层的调用,使得代码更多,但是如果是成百上千个请求呢,你难道每一次都像一种多写的那样,不断重复写wx.request请求???哈哈,真香警告
4、关键的代码promisic()方法
1 const promisic = function(func) { 2 return function(params = {}) { 3 return new Promise((resolve, reject) => { 4 const args = Object.assign(params, { 5 success: (res) => { 6 resolve(res); 7 }, 8 fail: (error) => { 9 reject(error); 10 } 11 }); 12 func(args); 13 }); 14 }; 15 } 16 17 export { 18 promisic 19 }
至于这段代码不做解释,因为我也不是很懂,尴尬了,不过这里用到的是设计模式中的代理模式,封装了一下Promise对象,将原生的API的success和fail函数去执行Promise对象的resolve和reject函数,从而达到封装成Promise对象的目的
五、终极项目结构
最终的结构一般会是这样子:
跟着七月老师继续努力!!!
七月老师课程链接:https://class.imooc.com/sale/javafullstack
async和await讲解:https://segmentfault.com/a/1190000011526612
原文地址:https://www.cnblogs.com/ssh-html/p/11726278.html
- Windows 7的VPC虚拟机自动不与主机时间同步的解决办法
- [C#1] 9-委托
- jquery基本选择器
- rainyday.js——超逼真全屏雨滴模拟插件
- [C#1] 8-数组
- ASP.NET MVC2 数据模型验证类库:MVC Foolproof Validation
- [C#1] 7-枚举
- 在链接前面自动添加favicon 图标(jquery)
- zepto 基础知识(4)
- Intro.js:网站功能操作分布引导插件(附中文独家使用教程)
- [C#1] 6-方法
- 如何删除WordPress 的“多站点”模式(multisite)?
- 部分Sonos及Bose扬声器爆安全漏洞,被黑客入侵后发出特定音频
- TCP - WAIT状态及其对繁忙的服务器的影响
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- leetcode之最短补全词
- React基础(10)-React中编写样式CSS(styled-components)
- 十大经典排序算法 (动态演示 + 代码)
- 学生成绩管理系统案例
- C 语言指针详解
- 04 CentOS6.5系统语言切换为中文
- 【SpringBoot DB 系列】Redis 高级特性之 Bitmap 使用姿势及应用场景介绍
- 踩坑:一次年轻代GC长暂停问题的解决与思考
- 监听MySQL的binlog日志工具分析:Canal
- 小解c# foreach原理
- 3分钟短文:任命管理员,给Laravel普通用户提权
- this到底是什么?
- ES5面向对象基础
- 面试官问我啥是OAuth 2.0,两个案例讲懂他~
- 年轻代频繁ParNew GC,导致http服务rt飙高