预期的mock的使用方式

首先我们从使用的角度出发,思考编码过程

  • M1. 通过配置文件配置url和response

  • M2. 自动检测环境为开发环境时启动Mock.js

  • M3. mock代码能直接覆盖global.fetch方法或者XMLHttpRequest构造函数,实现开发无感知

  • M4. mock配置不影响实际的请求,可无缝切换为实际请求

M1. 通过配置文件配置url和response

比较符合我们使用习惯的,也许是下面这种mock方式,有一个专门的配置文件,管理请求的url和返回值。每个请求对应输出数组中的一个对象,对象的rule属性可以是一个字符串或者一个正则表达式,用来匹配url,对象的res属性则是我们希望的从中请求中拿到的返回的数据 (也许这里面还应该加个type表示请求的类型,但是我这个是mock的最简化版,所以就不加了)

// api.js
module.exports = [
{
rule: '/mock',
res: {
a: 'data',
b: [{c: 1}, {d: 1}],
},
},
{
rule: '/mock2',
res: {
j: {
k: 'XXX'
},
},
},
];

M2. 自动检测环境为开发环境时启动Mock.js

// __DEV__ 可能是webpack等配置的全局变量
if (__DEV__) {
require ('./ajaxMock.js');
require ('./fetchMock.js');
}

M3. mock代码能直接覆盖global.fetch方法或者XMLHttpRequest构造函数,实现开发无感知

// fetchMock.js
window.fetch = function (url) {
// 覆盖默认fetch
}
// ajaxMock.js
class XMLHttpRequest {
// ...覆盖默认XHR
}
window.XMLHttpRequest = XMLHttpRequest;

M4.mock配置不影响实际的请求,可无缝切换为实际请求

mock配置不影响实际的请求,当请求没有命中mock配置文件中的url时,自动切换为实际请求,例如

// fetch
window.fetch = (url, cfg) => {
if (命中config文件中的url) {
// 覆盖默认fetch
} else {
return originFetch (url, cfg);
}
};
// Ajax
const RealXHR = window.XMLHttpRequest;
class XMLHttpRequest {
open (type, url, bool) {
if (命中config文件中的url) {
// 覆盖Ajax
} else {
// 使用系统原有的Ajax
this.xhr = new RealXHR ();
this.xhr.open (type, url, bool);
}
}
send (args) {
if (命中config文件中的url) {
// 覆盖Ajax
} else {
// 使用系统原有的Ajax
this.xhr.send (args);
}
}
}
window.XMLHttpRequest = XMLHttpRequest;

模拟fetch

直接上代码

// 保存系统原生的fetch
const originFetch = window.fetch; // 根据fetch的要求返回的response
const normalize = resp => {
return {
ok: true,
status: 200,
text () {
return Promise.resolve (resp);
},
json () {
return Promise.resolve (resp);
},
};
}; // 覆盖fetch
window.fetch = (url, cfg) => {
// url所对应的JSON对象
let res;
// 表示是否config文件中是否有和url对应的配置
let hit = false;
// 遍历配置文件中输出的数组,检测并尝试获取匹配url的res对象
fakeApi.forEach (item => {
let rule = item.rule;
if (typeof rule === 'string') {
rule = new RegExp (rule);
}
if (rule && rule.test (url)) {
res = item.res;
hit = true;
return false;
}
});
// 如果命中,那么返回一个Promise,并且传递上面和url匹配的JSON对象
if (hit) {
return new Promise (resolve => {
setTimeout (() => {
resolve (normalize (res));
}, 1000);
});
}
// 如果没有命中,那么使用系统原有的fetch的API,实现无缝切换
return originFetch (url, cfg);
};

模拟ajax

直接上代码

// 保存系统原生的XMLHttpRequest对象
const RealXHR = window.XMLHttpRequest; class XMLHttpRequest {
constructor () {
this.url = null;
this.type = null;
this.hit = false;
// 真实的xhr
this.xhr = null;
}
open (type, url, bool) {
// 遍历配置文件中输出的数组,检测并尝试获取匹配url的res对象
fakeApi.forEach (item => {
let rule = item.rule;
if (typeof rule === 'string') {
rule = new RegExp (rule);
}
if (rule && rule.test (url)) {
this.res = item.res;
this.hit = true;
return false;
}
});
// 如果没有命中,那么使用系统原有的Ajax的API,实现无缝切换
if (!this.hit) {
this.xhr = new RealXHR ();
this.xhr.open (type, url, bool);
}
}
send (args) {
// 如果命中,就覆盖Ajax的API
if (this.hit && this.onreadystatechange) {
this.readyState = 4;
this.status = 200;
this.responseText = JSON.stringify (this.res);
this.onreadystatechange ();
} else {
// 如果没有命中,那么使用系统原有的Ajax的API,实现无缝切换
this.xhr.send (args);
}
}
}
// 覆盖
window.XMLHttpRequest = XMLHttpRequest;

测试

配置文件

export default [
{
rule: '/mock',
res: {
a: 'data',
b: [{c: 1}, {d: 1}],
},
}
];

测试代码

const xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log (JSON.parse (xhr.responseText));
}
};
xhr.open ('GET', '/mock');
xhr.send ();

测试结果

额外扩展

除了上面的功能外,我们还能做什么?

  • 加个type类型,区分同一url下的不同请求类型,例如get,post

  • 加个布尔值err,表示失败的请求

上面这两个功能再做了我觉得就已经很足够了,当然,如果你还不满足,那你还可以尝试:

  • 处理xhr.open的第三个参数:async值,控制同步和异步

  • 处理xhr的progress,load,error,abort等事件监听

  • 处理fetch返回的response的其他方法,例如Body.formData()等等

再谈mock.js

早在之前我就写过一篇关于mock.js的文章。这个库目前在github是13k, 当然我觉得这个库是很强大的,因为它覆盖了从名字,地名,文章甚至是图片资源的mock数据,但是在实际使用中却多少有那么一点点“鸡肋”的感觉,为什么我会有这样一种感觉呢

这是因为它有一套自己的独立的模板语法,以及API,需要你学习和遵循

// 模拟JSON数据
Mock.mock({
"array|1-10": [
"Hello",
"Mock.js",
"!"
]
})
// 模拟大段的文章或句子
Random.paragraph( min?, max? )

当然mock.js有它自己的好处,例如:

  • 当你需要动态地造大数据量的mock数据的时候很方便,例如mock.js的Random.paragraph的API能很方便的帮你造出来

  • 当你有一些特殊的需求点的时候,例如一个长度宽度变化的图片的时候,mock.js也可以很强大的胜任Random.image( size?, background?)

  • 造出来的数据看起来“很漂亮很真实”,单纯看完全发现不了是假的数据

但问题在于,我在实际的开发中发现,我们大多数的数据场景根本就没这么复杂

我们大多数时候需要的仅仅只是:写一个响应数据的模版,例如一个json文件,然后使得发一个请求过去的时候能在ajax的onreadystatechange或者fetch(url).then中拿到数据就可以了

如果符合我们预期的mock的“完美需求”是100%的话

mock.js这个社区应用实现了80%到99%的需求的过程

但是它的使用方式却额外增加了30% ~ 40%的成本,

因为,我们大多数时候也许不太需要这么多的模板和“看起来很漂亮的数据”

这是我写这个简易版的mock的实现的原因


才疏学浅,还多指教,本文完

来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)的更多相关文章

  1. 手写一个简易版Tomcat

    前言 Tomcat Write MyTomcat Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器.那么想一想,Tomcat和我们的Web应用是什么关系? 从感性上 ...

  2. 手写一个简版 asp.net core

    手写一个简版 asp.net core Intro 之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架,最近参考蒋老师和 Edison 的文章和代码,结合自己对 asp ...

  3. 手写一个简易的IOC

    这个小项目是我读过一点Spring的源码后,模仿Spring的IOC写的一个简易的IOC,当然Spring的在天上,我写的在马里亚纳海沟,哈哈 感兴趣的小伙伴可以去我的github拉取代码看着玩 地址 ...

  4. 手写一个简易的多周期 MIPS CPU

    一点前言 多周期 CPU 相比单周期 CPU 以及流水线 CPU 实现来说其实写起来要麻烦那么一些,但是相对于流水线 CPU 和单周期 CPU 而言,多周期 CPU 除了能提升主频之外似乎并没有什么卵 ...

  5. 手写Promise简易版

    话不多说,直接上代码 通过ES5的模块化封装,向外暴露一个属性 (function(window){ const PENDING = 'pending'; const RESOLVED = 'fulf ...

  6. 用python 10min手写一个简易的实时内存监控系统

    简易的内存监控系统 本文需要有一定的python和前端基础,如果没基础的,请关注我后续的基础教程系列博客 文章github源地址,还可以看到具体的代码,喜欢请在原链接右上角加个star 腾讯视频链接 ...

  7. [转]用python 10min手写一个简易的实时内存监控系统

    简易的内存监控系统 本文需要有一定的python和前端基础,如果没基础的,请关注我后续的基础教程系列博客 文章github源地址,还可以看到具体的代码,喜欢请在原链接右上角加个star 腾讯视频链接 ...

  8. 手写一个简单版的SpringMVC

    一 写在前面 这是自己实现一个简单的具有SpringMVC功能的小Demo,主要实现效果是; 自己定义的实现效果是通过浏览器地址传一个name参数,打印“my name is”+name参数.不使用S ...

  9. 手写spring(简易版)

    本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正! 理解Spring本质: 相信之前在使用spring的时候大家都配置web.x ...

随机推荐

  1. CocosCreator 快速开发推箱子游戏,附代码

    游戏总共分为4个功能模块: - 开始游戏(menuLayer) - 关卡选择(levelLayer) - 游戏(gameLayer) - 游戏结算(gameOverLayer) Creator内组件效 ...

  2. .NET Core使用gRPC打造服务间通信基础设施

    一.什么是RPC rpc(远程过程调用)是一个古老而新颖的名词,他几乎与http协议同时或更早诞生,也是互联网数据传输过程中非常重要的传输机制. 利用这种传输机制,不同进程(或服务)间像调用本地进程中 ...

  3. 你的火狐很慢吗? - Firefox启动和运行速度优化

    最近刚开始体验firefox,发现了一些优势和缺点,无敌的扩展确实带来的是功能上的享受,可随之而来的问题便是太多的插件和主题导致ff启动如龟速,比起IE和TW都有不小的差距,因此特意搜集来一些关于启动 ...

  4. Vue使用vue-recoure + http-proxy-middleware + vuex配合promise实现基本的跨域请求封装

    使用vue init webpack 你的项目名称初始化一个vue的项目 安装依赖 npm install vue-resource http-proxy-middleware vuex koa 在项 ...

  5. Detours 劫持

    在使用 Detours 劫持之前必须得拥有这两个东西:detours.h 和 detours.lib. 为了这两个东西我真的是弄了大半天,本着自己动手丰衣足食的思想: 我去 GitHub 克隆了一份来 ...

  6. Zeppelin的安装和SparkSQL使用总结

    zeppelin是spark的web版本notebook编辑器,相当于ipython的notebook编辑器. 一Zeppelin安装 (前提是spark已经安装好) 1 下载https://zepp ...

  7. 《深入理解Java虚拟机》-----第10章 程序编译与代码优化-早期(编译期)优化

    概述 Java语言的“编译期”其实是一段“不确定”的操作过程,因为它可能是指一个前端编译器(其实叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是指虚拟机的后端运 ...

  8. 扩展阿里p3c实现自定义代码规范检查

     前段时间fastjson报出了漏洞,只要打开setAutoType特性就会存在风险,自己测试环境的一个项目被揪出来了-_-!.虽然改动很小,但就是觉得憋屈.fastjson还是挺好的,想着禁用的话太 ...

  9. Python编程系列---使用字典实现路由静态路由

    def index(): print('Index Page....') def bbs(): print('BBS Page....') def login(): print('Login Page ...

  10. 无情的Java 8 之 Stream和lambda表达式篇

    不好意思,最近刷小视频刷的有点上头 看到这图就不自觉的要来一句:"卧槽,无情" 好了,我要开始正经了 JAVA 8 已经推出有一段时间了, 相比之前, 我们操作集合的方式应该是这样 ...