最近想用全js系统的写一遍前后端学习一下,就创建了一套TODOList项目练手。当前仅写完了后端demo,前端正在使用vue。并且准备以后再用react和flutter再写一遍。
前提
在写练手项目的时候使用了Framework7
这个移动端ui框架,因为这个框架的动画写的很厉害所以选择了它。但是在使用过程中,发现这个框架自带的ajax请求库特别简单,于是参照axios
手动封装了一下,使其支持promise和拦截器。
动手
废话不多说,上代码comover.js
import { Request as F7Request } from "framework7";
// 将原始请求对象封装成Promise对象
function adapter(config) {
return new Promise(function(resolve, reject) {
F7Request({
url: `${config.baseUrl}${config.url}`,
method: config.method,
headers: config.headers,
data: config.data,
success(data, status, xhr) {
resolve({
data: JSON.parse(data),
status: status,
config: config,
xhr: xhr
});
},
error(xhr, status) {
let error = new Error(
`Request failed with status code ${status}`
);
error.xhr = xhr;
reject(error);
}
});
});
}
// 发送请求
function dispatchRequest(config) {
return adapter(config).then(
function onAdapterResolution(response) {
return response;
},
function onAdapterRejection(reason) {
return Promise.reject(reason);
}
);
}
export default class Comeover {
interceptors = {};
requestHandlers = [];
responseHandlers = [];
config = {};
constructor(config = ({ baseUrl = "" } = {})) {
const self = this;
this.config = { ...config };
this.interceptors = {
request: {
use(fulfilled, rejected) {
self.requestHandlers.push({
fulfilled,
rejected
});
}
},
response: {
use(fulfilled, rejected) {
self.responseHandlers.push({
fulfilled,
rejected
});
}
}
};
// ES6中class内方法运行时绑定上下文
this.request = this.request.bind(this);
}
request(config) {
// 合并默认config和发送请求时的config
let inconfig = { ...this.config, ...config };
// 创建Promise链
let chain = [dispatchRequest, undefined];
// 创建初始Promise链中传递的promise对象
let promise = Promise.resolve(inconfig);
// 将拦截器注入Promise链
this.requestHandlers.forEach(interceptor => {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.responseHandlers.forEach(interceptor => {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
// 运行Promise链
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
// 返回最终的promise对象
return promise;
}
}
使用
这个例子就是在所有请求前后使用nprogress假装显示一下请求进度
import Comeover from "./comeover";
import Np from "nprogress";
const baseUrl = process.env.NODE_ENV === "development" ? "" : /* 上线地址 */ "";
const comeover = new Comeover({ baseUrl });
comeover.interceptors.request.use(
config => {
Np.start();
return config;
},
error => {
Np.done();
return Promise.reject(error);
}
);
comeover.interceptors.response.use(
response => {
Np.done();
return response;
},
error => {
Np.done();
return Promise.reject(error);
}
);
export { request };
发请求
comeover.request({
url: "/api/login",
method: "post",
data: {
email: this.email,
password: this.password
}
})
.then(({ data }) => {
this.$store.commit("login", { token: data.message });
router.back();
})
.catch(err => {
app.dialog.alert("用户名或密码错误", "登陆失败");
});
总结
还可以参照axios
继续封装单独的get、post等等的方法,这个demo就不写了。
Promise链是个数组,然后把请求拦截器放到真正请求的前面,响应后的拦截器放在真请求的后面。然后以resolve
在前,reject
在后的顺序,成对循环注入到promise.then
中。而真正请求的resove
和reject
是写在dispatchRequest
里的,所以dispatchRequest
这里没有reject,要加一个undefined
。
ES6的实例化方法单独使用的时候this指向会有问题,需要单独处理