最近想用全js系統的寫一遍先後端學習一下,就建立了一套TODOList項目練手。當前僅寫完了後端demo,前端正在使用vue。而且準備之後再用react和flutter再寫一遍。
此項目
後端demo
在寫練手項目的時候使用了Framework7
這個移動端ui框架,由於這個框架的動畫寫的很厲害因此選擇了它。可是在使用過程當中,發現這個框架自帶的ajax請求庫特別簡單,因而參照axios
手動封裝了一下,使其支持promise和攔截器。javascript
廢話很少說,上代碼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僞裝顯示一下請求進度vue
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指向會有問題,須要單獨處理java