基於promise封裝自己的Ajax庫
阿新 • • 發佈:2021-06-19
/** * 支援的功能 * 1.支援全域性預設配置項 * 2.傳送請求_ajax.get/post.. * 3.每一次請求都會返回promise例項,基於promise設計模式管理 * 4.支援_ajax.all * 5.有實現攔截器這個功能 */ ~function(){ //封裝Ajax類 class MyAjax{ constructor(url,options){ this.url = url; this.options = options return this.init(); } //傳送ajax請求(基於promise來管理) init(){ //進行解構 let { url, potions: { baseURl, withCredentials, headers, transformRequest, transformResponse, validateStatus, params, data, caches, methods } }=this; //保證響應攔截器中資訊的合法性 !Array.isArray(transformResponse) ? transformResponse = [] : null; new Array(2).fill(null).forEach((item,index)=>{ typeof transformResponse[index] !== 'function' ? transformResponse[index] = null : null; }) return new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest; //URL的處理 url = baseURl+url; if(/^(GET|DELETE|HEAD|OPTIONS)$/i.test(methods)){ if(params){ let result = ``; for(let attr in params){ if(!params.hasOwnProperty(attr)) break; result = `&${attr}=${params[attr]}`; } result = result.substring(1); url += `${url.indexOf('?')===-1?'?':'&'}${result}`; } if(caches===false){ url += `${url.indexOf('?')===-1?'?':'&'}_=${Math.random()}`; } } xhr.open(methods,url); xhr.onreadystatechange=()=>{ let resultFlag = validateStatus(xhr.status); if(!resultFlag){ reject({ status:xhr.status, statusText: xhr.statusText, request = xhr }); return; } if(xhr.readyState === 4){ //把所有響應頭變成鍵值對方式 let res_headers = {}; xhr.getAllResponseHeaders().split(/\n/).forEach(item=>{ let [key='',value=''] = item.split(':'); if(key.trim()==='')return; res_headers[key.trim()] = value.trim(); }); resolve({ status: xhr.status, statusText: xhr.statusText, request = xhr, data: JSON.parse(xhr.responseText), headers : res_headers }); } } // 跨域處理 xhr.withCredentials = withCredentials; //設定請求頭 if(headers){ for(let attr in headers){ if(!headers.hasOwnProperty(attr))break; xhr.setRequestHeader(attr,encodeURI(headers[attr])) } } //請求攔截器:請求主體傳遞資訊的攔截 對data的處理 if(/^(POST|PUT)$/i.test(methods)){ typeof transformRequest === 'function' ? data = transformRequest(data) : null; }else{ data = null; } xhr.send(); }).then(...transformResponse); //保證在執行自己的then()之前,執行攔截器,在建立完promise例項之後直接設定攔截器的then方法 } } function _init(options){ //將_ajax.defaults和函式中的options引數進行匹配合並 /** * 引數初始化:headers需要特殊處理(把使用者options中傳遞的headers和defaults中的headers進行合併,而不是整體替換), * 其餘的配置項直接用options中的替換defaults中的即可 * */ let optionsHeaders = options.headers; _ajax.defaults.headers = Object.assign(_ajax.defaults.headers,optionsHeaders) delete options.headers; return Object.assign(_ajax.defaults,options); } function _ajax(){ //建立全域性的預設配置 _ajax.defaults = { baseURl = '', withCredentials: false, //表示跨域請求時是否需要使用憑證 headers:{}, transformRequest: function (data) { // `transformRequest` 允許在向伺服器傳送前,修改請求資料 if(!data) return data; let str = ``; //迴圈data for(let key in data){ if(!data.hasOwnProperty(key))break; str = `&${key}=${data[key]}`; } return str.substring(1);; }, transformResponse: [function onFulfilled(response){ // `transformResponse` 在傳遞給 then/catch 前,允許修改響應資料 return response.data; },function onRejected(reason){ return Promise.reject(reason); }], validateStatus: function (status) { //http的響應狀態碼 return /^(2|3)\d{2}$/.test(status); }, //請求配置項 params:{}, data:{}, caches: true } ["get","delete","head","options"].forEach(item=>{ options.methods = item; _ajax[item] = function(url,options={}){ return new MyAjax(url,_init(options)); } }); ["post","put"].forEach(item=>{ _ajax[item] = function(url,data={},options={}){ //把data也放到配置專案 options.data = data; options.methods = item; return new MyAjax(url,_init(options)); } }) _ajax.all = function all(promiseArr = []){ return Promise.all(promiseArr); } } window._ajax = _ajax; //對全域性暴露_ajax; }();