前端的轮子们

前端的新轮子层出不穷,这里集中记录一下。

Mock

如果将mock单独翻译过来,其意义为 “虚假、虚设”,因此在软件开发领域,我们也可以将其理解成 “虚假数据”,或者 “真实数据的替身”

Mock的好处

  • 团队可以更好地并行工作

当使用mock之后,各团队之间可以不需要再互相等待对方的进度,只需要约定好相互之间的数据规范(文档),即可使用mock构建一个可用的接口,然后尽快的进行开发和调试以及自测,提升开发进度的的同时,也将发现缺陷的时间点大大提前。

  • 开启TDD(Test-Driven Development)模式,即测试驱动开发

单元测试是TDD实现的基石,而TDD经常会碰到协同模块尚未开发完成的情况,但是有了mock,这些一切都不是问题。当接口定义好后,测试人员就可以创建一个Mock,把接口添加到自动化测试环境,提前创建测试。

  • 测试覆盖率

比如一个接口在各种不同的状态下要返回不同的值,之前我们的做法是复现这种状态然后再去请求接口,这是非常不科学的做法,而且这种复现方法很大可能性因为操作的时机或者操作方式不当导致失败,甚至污染之前数据库中的数据。如果我们使用mock,就完全不用担心这些问题。

  • 方便演示

通过使用Mock模拟数据接口,我们即可在只开发了UI的情况下,无须服务端的开发就可以进行产品的演示。

  • 隔离系统

在使用某些接口的时候,为了避免系统中数据库被污染,我们可以将这些接口调整为Mock的模式,以此保证数据库的干净。

在吹了这么多的Mock之后,相信大家一定跃跃欲试了,那么接下来我们谈一谈实现Mock的几种方法。

Mock实现

mockJs,通过使用mockJs我们能根据模板和规则生成复杂的接口数据,而无需我们自己动手去书写,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// api
import api from '../api/index';
import Mock from 'mockjs';

function getApiMessage() {
return new Promise((resolve) => {
resolve(Mock.mock({
list|1-20: ['mock数据']
});
})
// return api.getApiMessage();
}
/**
* 通过 Mock.mock 方法和 list|1-20: ['mock数据'] 模板
* 我们将生成一个长度为 1-20, 每个值都为 'mock数据' 数组
*/

但是这样做始终只不过是方便了我们“造假”而已,并不能将“假货”真的从我们的业务代码中移除出去。为了实现这个目的,我们不妨先来分析我们的需求:

  • 模拟数据与业务代码完全分离
  • 通过一些配置,达到只mock部分数据,大部分的数据还是从请求中获取

首先,如果我们要想要模拟数据和业务代码完全分离,我们必须要想办法在请求的时候做一些文章,让其在请求的时候去获取mock数据而非去请求真正的接口,也就是所谓的“请求拦截”,而实现请求拦截也同样有两种方式:

  • 修改请求链接到mock-server,在mock-server配置mock数据和路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// api/index.js
// 通过新增getDataUseMock方法来说明使用了mock方法
import request from '../request';

function getDataUseMock(data) {
request({
mock: true
});
}
// request/index.js
const mockServer = 'http://127.0.0.1:8081';

function request(opt) {
if (opt.mock) {
const apiName = opt.api;
opt.url = `${mockServer}/${apiName}`;
}
...
}
复制代码
  • 直接在检测使用mock时,从mock数据文件中取出对应key值的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// api/index.js
// 通过新增getDataUseMock方法来说明使用了mock方法
import request from '../request';

function getDataUseMock(data) {
request({
mock: true
});
}

// request/index.js
import mockData from 'mock/db.js';

function request(opt) {
if (opt.mock) {
const apiName = opt.api;
return new Promise((resolve) => {
resolve(mockData.apiName)
})
}
...
}

//mock/db.js
export default {
'/api/test': {
msg: '请求成功'
}
}
复制代码

乍一看好像第二种方式似乎更简单,事实也确实如此,但是考虑到如果我是直接从文件中直接读取数据,那么业务上的行为也会改变,该发请求的地方并没有发请求,所以我还是选择了自己搭建一个本地的服务,通过控制路由返回不同的mock数据来处理,并且通过为请求增加一个额外mock参数通知业务哪些接口应当被自建的mock-server拦截,从而尽量减少对原有业务的影响。

mock-server开发之前,我们需要明白我们的mock-server应当能做哪些事情:

  • 所改即所得,具有热更新的能力,每次增加 /修改 mock 接口时不需要重启 mock 服务,更不用重启前端构建服务
  • mock 数据可以由工具生成不需要自己手动写
  • 能模拟 POST、GET 请求

因为mock的模拟数据都在本地维护,我们所需要的只要是个无界面的能够响应请求的server即可,所以我选择了json-server

在构建server之前,我们先要明确我们需要模拟的数据是什么,以及用什么(mockjs)去维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// db.js
var Mock = require('mockjs');

// 通过使用mock.js,来避免手写数据
module.exports = {
getComment: Mock.mock({
"error": 0,
"message": "success",
"result|40": [{
"author": "@name",
"comment": "@cparagraph",
"date": "@datetime"
}]
})
};
复制代码

其次我们要知道我们跳转的访问路由是哪些:

1
2
3
4
5
6
// routes.js
// 根据db.js中的key值,自动生成的路由便是/[key],在route.js中的声明只是为了重定向
module.exports = {
"/comment/get": "/getComment"
}
复制代码

然后我们就可以书写我们启动server的主要代码了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// server.js
const jsonServer = require('json-server')
const db = require('./db.js')
const routes = require('./routes.js')
const port = 3000;

const server = jsonServer.create()
// 使用mock的数据生成对应的路由
const router = jsonServer.router(db)
const middlewares = jsonServer.defaults()
// 根据路由列表重写路由
const rewriter = jsonServer.rewriter(routes)

server.use(middlewares)
// 将 POST 请求转为 GET,满足可以接受 POST 和 GET 请求的需求
server.use((request, res, next) => {
request.method = 'GET';
next();
})

server.use(rewriter) // 注意:rewriter 的设置一定要在 router 设置之前
server.use(router)

server.listen(port, () => {
console.log('open mock server at localhost:' + port)
})
复制代码

由此,只要使用node server.js便能够启动一个mock-server了,但是这样启动的server,并不能因为我修改route.js或者db.js而实时更新,也就是说,我需要每次都重启一次才能更新我的server,这里还需要我们进行一个小操作,比如使用nodemon来监控我们的mock-server.

1
2
3
4
5
6
// 将所有和mock相关的文件:db.js route.js server.js 放入mock文件夹
// 然后执行:
$ nodemon --watch mock mock/server.js

// 就能够启动一个能自动热更新的mock-server了。
复制代码

这之后,我们只需要在自己的业务代码中,使用我们之前定义的类似于getDataUseMock的方法,就可以对指定API进行mock啦。

虽然我们这样做已经完成了mock数据和业务代码的完全分离,但是还是不可避免的在业务代码中使用了特殊的方法来声明我需要mock某个接口,还是同样要面对当不需要mock时,要删除这些方法并替换成正式请求的方法的问题。而且mock数据的部分仍然放在和业务代码一个git目录下,只有开发者才有权限去修改和增加,并没有很好地达到mock应当有的作用。

为此,我征求了部门Leader和“广大”开发者的意见,确定了我们需要的mock应当是怎样的:

  • 尽量少的修改业务中的代码就能使用mock
  • 修改的业务代码不会影响正常的业务流程
  • mock-server 应当是面向所有人,而不只是前端开发者
  • 能够可视化的修改和增加 mock 接口和 mock 数据
  • 能够同时支持多个项目使用

在这几个基本原则的帮助下,我们的mock终于晋级到了“永恒钻石”段位。

类似mockjs的mock工具还有 EasyMock

参考链接

作者:santree 链接:https://juejin.im/post/5bd82d796fb9a05d25682a66 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Lint

代码检查工具

TypeScript & JavaScript

JS就是蹭当年Java的热度起的名字,JavaScript这个名字和Java没半点关系,Java里的接口、继承、强类型,它都没有。而TS是JS的超集,正是补全了上面那些缺失的部分,强调的是TypeScript。有了强类型,就有了更好的IDE支持,包括语法提示和编译时错误信息。有了接口和继承,代码就更易读易维护。这些都是大型复杂前端工程急需的特性。

  • 语言层面:JavaScript和TypeScript都是ECMAScript(ECMA-262)的具体实现。
  • 执行环境层面:浏览器引擎和Node.js都能够直接运行JavaScript,但无法直接运行TypeScript。
  • 时序层面:TypeScript被真正执行前,会通过编译转换生成JavaScript,之后才能被解释执行。
  • 厂商层面:JavaScript由Netscape率先推出,现在主要由各大浏览器厂商实现。而TypeScript is a trademark of Microsoft Corporation,目前由微软进行设计和维护。

作者:郭凯 链接:https://www.zhihu.com/question/334938460/answer/782030856 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!