共计 2755 个字符,预计需要花费 7 分钟才能阅读完成。
最近想用全 js 系统的写一遍前后端学习一下,就创建了一套 TODOList 项目练手。当前仅写完了后端 demo,前端正在使用 vue。并且准备以后再用 react 和 flutter 再写一遍。
此项目
后端 demo
前提
在写练手项目的时候使用了 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 指向会有问题,需要单独处理
正文完
发表至: javascript
2019-08-23