1. 程式人生 > 其它 >基於promise封裝自己的Ajax庫

基於promise封裝自己的Ajax庫

/**  
 * 支援的功能
 *  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;
}();