成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

前端項(xiàng)目請求層封裝過程

bbbbbb / 2783人閱讀

摘要:我們看下把重復(fù)代碼封裝成一個(gè)的示例代碼這里假設(shè)我們項(xiàng)目請求頭固定這兩個(gè)判斷返回沒有錯(cuò)誤使調(diào)用可讀性更好以上封裝了一個(gè),調(diào)用的時(shí)候如下對結(jié)果進(jìn)行處理通過傳遞回調(diào)函數(shù)的方式,可讀性性不是很好當(dāng)然這是一個(gè)仁者見仁的問題。

調(diào)用 ajax 取請求后端數(shù)據(jù)是項(xiàng)目中最基礎(chǔ)的功能。但是如果每次直接調(diào)用底層的瀏覽器 api 去發(fā)請求則非常麻煩。現(xiàn)在來分析一下怎么封裝這一層,看看有哪些基礎(chǔ)問題需要考慮。本文底層使用 fetch ,如果你使用 XMLHttpRequest 甚至第三方庫(譬如:axios)封裝過程都是大同小異的。

封裝重復(fù)代碼

對于同一個(gè)項(xiàng)目通常來說請求參數(shù)有很多重復(fù)的內(nèi)容,譬如 url 的拼接,http head 的設(shè)置。假設(shè)我們調(diào)用的是 RESTful 接口,通常我們需要變動(dòng)的有:1. 請求 url 的 path 部分;2. 參數(shù);3. 請求 method;4. 成功/失敗回調(diào)函數(shù)。我們看下把重復(fù)代碼封裝成一個(gè) ApiSender 的示例代碼:

const URL_PREFIX = "xxx";

let ApiSender = {
  send( options ) {
    let {
      path,
      params,
      method,
      success,
      fail
    } = options;

    let url = URL_PREFIX + path;
    if ( method==="GET" ) {
      url += ("?"+toQueryString( params ));
    }
    let requestBody;
    if ( method==="POST" ) {
      requestBody = params;
    }

    fetch( url, {
      method: method,
      // 這里假設(shè)我們項(xiàng)目請求頭固定這兩個(gè)
      headers: {
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
      },
      credentials: "include",
      body: requestBody
    } ).then( function(response){
      let resultJson = response.json();
      if ( /* 判斷返回沒有錯(cuò)誤 */ ) {
        success && success( resultJson );
      } else {
        fail && fail( resultJson.error );
      }
    } );
  }
}
使調(diào)用可讀性更好

以上封裝了一個(gè) ApiSender,調(diào)用的時(shí)候如下:

ApiSender.send( "/resource", "GET", {
  pageSize: 10,
  pageNo: 1
}, function( result ){
  // 對結(jié)果進(jìn)行處理
}, function( error ){
  alert( error )
} )

通過傳遞回調(diào)函數(shù)的方式,可讀性性不是很好(當(dāng)然這是一個(gè)仁者見仁的問題)。我們把返回改成 Promise。因?yàn)槲覀冇玫氖?fetch,它直接返回的就是 Promise,比較好改。如果你底層用的是 XMLHttpRequest,那么可以自行把調(diào)用 XMLHttpRequest 的代碼封裝在一個(gè) Promise 中返回。

let ApiSender = {
  send( options ) {
    let {
      path,
      params,
      method,
      success,
      fail
    } = options;

    let url = URL_PREFIX + path;
    if ( method==="GET" ) {
      url += toQueryString( params );
    }
    let requestBody;
    if ( method==="POST" ) {
      requestBody = params;
    }

    return fetch( url, {
      method: method,
      // 這里假設(shè)我們項(xiàng)目請求頭固定這兩個(gè)
      headers: {
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
      },
      credentials: "include",
      body: requestBody
    } ).then( function(response){
      return response.json()
    } );
  }
}

調(diào)用的時(shí)候代碼就變成:

ApiSender.send( "/resource", "GET", {pageSize:10,pageNo:1} ).then( function(result){
  if ( /* 判斷返回沒有錯(cuò)誤 */ ) {
    // 處理結(jié)果
  } else {
    // 提示錯(cuò)誤
  }
} )
從調(diào)用者角度抽象返回值

上面代碼有一個(gè)問題,對于 ApiSend 的調(diào)用者來說,他需要直接處理接口返回值,判斷是否成功。如果接口返回對象比較簡單還好,如果非常復(fù)雜,那么調(diào)用者就很頭疼,舉個(gè)例子,我碰到過如下的接口返回值:

{
  content: {
    result: {
      errorCode: 1,
      errorMessage: "",
      isSuccess: true
    },
    data: {}|[] // 真正的可用數(shù)據(jù)
  },
  a: { // 有特征的字段名我做了簡化,使用了a,ab這樣的字段名。a 這個(gè)字段內(nèi)容是 api 網(wǎng)關(guān)層包裝的。
    code: 1,
    ab: [ {
      code: 1
    } ]
  }
}

如何判斷這個(gè)返回值是成功的呢?

let result = { /* 上面那個(gè)對象 */ }
if (
  result.a &&
  result.a.code === 0 &&
  result.a.ab &&
  result.a.ab[ 0 ] &&
  result.a.ab[ 0 ].code === 0
) {
  if (
    result.content &&
    result.content.result &&
    result.content.result.isSuccess === true
  ) {
    // 處理結(jié)果 result.content.data
  }
}

你想象下,作為 ApiSender 的調(diào)用方,會(huì)希望得到什么結(jié)果?執(zhí)行正確的時(shí)候獲得接口返回的數(shù)據(jù),執(zhí)行異常的時(shí)候獲得錯(cuò)誤信息。我不希望調(diào)用一個(gè)方法,需要通過復(fù)雜地解析返回值來判斷是否成功。所以最直觀的就是把錯(cuò)誤封裝成一個(gè)很直觀的返回值:

let ApiSender = {
  send( options ) {

    /* 代碼省略掉了 */

    return fetch( /* 參數(shù)也省略掉了 */ ).then( function(response){
      let result = response.json();
      if ( isSuccessResult(result) ) {
        return [ null, result.content.data ]
      } else {
        let error = parseError( result );
        return [ error, null ];
      }
    } );
  }
}

那么調(diào)用方對結(jié)果的判斷就非常方便了:

ApiSender.send( "/resource", "GET", {pageSize:10,pageNo:1} ).then( function([error,data]){
  if ( !error ) {
    // 處理結(jié)果 data
  } else {
    alert( error ); // error 的格式大家可以自行定義,各個(gè)項(xiàng)目各有不同
  }
} );
面向切面需要做些什么

以上一個(gè)比較基礎(chǔ)且簡潔的封裝就做好了,但是現(xiàn)實(shí)中有些基礎(chǔ)功能是經(jīng)常需要的,譬如請求日志,請求錯(cuò)誤報(bào)錯(cuò)統(tǒng)一處理。如果這些代碼需要調(diào)用方來做,一來代碼重復(fù),二來譬如日志應(yīng)該是調(diào)用方不感知的一個(gè)功能。所以我們對代碼進(jìn)一步進(jìn)行優(yōu)化,加入這些功能:

let ApiSender = {
  send( options ) {

    /* 代碼省略掉了 */

    return fetch( /* 參數(shù)也省略掉了 */ ).then( function(response){
      let result = response.json();
      // 記錄調(diào)用日志
      writeLog( options, result );

      if ( isSuccessResult(result) ) {
        return [ null, result.content.data ]
      } else {
        let error = parseError( result );
        // 界面報(bào)錯(cuò)
        MessageComponent.error( `${error.message}(${error.code})` );

        return [ error, null ];
      }
    } );
  }
}

日志你可以上傳服務(wù)器,也可以就本地 console,日志記錄哪些內(nèi)容,參數(shù)如何都按各自的項(xiàng)目需求而定。如此的話,調(diào)用方就更簡潔了:

ApiSender.send( "/resource", "GET", {pageSize:10,pageNo:1} ).then( function([error,data]){
  if ( !error ) {
    // 處理結(jié)果 data
  }
} );

絕大多數(shù)情況下,調(diào)用接口返回錯(cuò)誤是需要在頁面上提示錯(cuò)誤的,但是并不是所有情況都需要。譬如非用戶觸發(fā)的行為,且請求返回的結(jié)果并不嚴(yán)重影響頁面操作或者流程。那么我們可以在調(diào)用 ApiSender 的時(shí)候加一個(gè)參數(shù),允許調(diào)用方跳過全局錯(cuò)誤處理:

let ApiSender = {
  send( options ) {

    /* 代碼省略掉了 */
    let skipErrorHandler = options.skipErrorHandler;

    return fetch( /* 參數(shù)也省略掉了 */ ).then( function(response){
      let result = response.json();
      // 記錄調(diào)用日志
      writeLog( options, result );

      if ( isSuccessResult(result) ) {
        return [ null, result.content.data ]
      } else {
        let error = parseError( result );

        // 傳了這個(gè)參數(shù)才跳過,不傳或者傳了非 true 值(當(dāng)然包括 false),都認(rèn)為不跳過
        if ( skipErrorHandler===true ) {
          // 界面報(bào)錯(cuò)
          MessageComponent.error( `${error.message}(${error.code})` );
        }
        
        return [ error, null ];
      }
    } );
  }
}

所以如果你希望自己處理錯(cuò)誤,調(diào)用的時(shí)候代碼就是:

ApiSender.send( "/resource", "GET", {skipErrorHandler:true/*, 其他參數(shù) */} ).then( function([error,data]){
  if ( !error ) {
    // 處理結(jié)果 data
  } else {
    // 自行處理錯(cuò)誤
  }
} );

到這里為止,請求層的基本封裝算是比較完整了,不過最后有一個(gè)小點(diǎn)要考慮下,如果你在 fetch().then 傳入的回調(diào)函數(shù)中因?yàn)榉N種原因而拋出了異常(譬如某個(gè)字段沒有判空)。那么 ApiSender 的調(diào)用方是沒法感知的,程序直接就報(bào)錯(cuò)了。所以為了程序的健壯性,我們最后再加一個(gè) catch:

let ApiSender = {
  send( options ) {

    /* 代碼省略掉了 */
    let skipErrorHandler = options.skipErrorHandler;

    return fetch( /* 參數(shù)也省略掉了 */ ).then( function(response){
      let result = response.json();
      // 記錄調(diào)用日志
      writeLog( options, result );
      if ( isSuccessResult(result) ) {
        return [ null, result.content.data ]
      } else {
        let error = parseError( result );
        // 傳了這個(gè)參數(shù)才跳過,不傳或者傳了非 true 值(當(dāng)然包括 false),都認(rèn)為不跳過
        if ( skipErrorHandler===true ) {
          // 界面報(bào)錯(cuò)
          MessageComponent.error( `${error.message}(${error.code})` );
        }
        
        return [ error, null ];
      }
    } ).catch( function(error){
      return [ error, null ];
    } );
  }
}

這樣一個(gè)對調(diào)用方友好,避免代碼重復(fù)的請求層就封裝好了。PS: 如果對 Promise 的 api 不是很熟悉的話,可以先了解下,有助于更好的理解示例代碼。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/103262.html

相關(guān)文章

  • 前端開發(fā) 面試 精選

    摘要:用戶填寫所有信息后,提交給服務(wù)器,等待服務(wù)器的回應(yīng)檢驗(yàn)數(shù)據(jù),是一次性的。移除的元素包括純表現(xiàn)的元素對可用性產(chǎn)生負(fù)面影響的元素。網(wǎng)頁的行為層負(fù)責(zé)回答內(nèi)容應(yīng)該如何對事件做出反應(yīng)這一問題。他是指一種創(chuàng)建交互式網(wǎng)頁應(yīng)用的網(wǎng)頁開發(fā)技術(shù)。 AngularJS。 優(yōu)點(diǎn): 模板功能強(qiáng)大豐富,并且是聲明式的,自帶了豐富的Angular指令; 是一個(gè)比較完善的前端MV*框架,包含模板,數(shù)據(jù)雙向綁定,路由...

    李文鵬 評論0 收藏0
  • 關(guān)于個(gè)人開源項(xiàng)目(vue app)的一些總結(jié)

    摘要:關(guān)于個(gè)人開源項(xiàng)目的一些總結(jié)項(xiàng)目地址項(xiàng)目簡介此項(xiàng)目名叫。網(wǎng)站目前實(shí)現(xiàn)了登錄注冊日歷導(dǎo)入文件考勤導(dǎo)出缺勤名單等核心功能。這對于小型項(xiàng)目來說并沒有什么問題。編譯后的大小關(guān)于文件上傳與導(dǎo)出功能文件上傳導(dǎo)出可以說是此項(xiàng)目最關(guān)鍵的點(diǎn)了。 關(guān)于個(gè)人開源項(xiàng)目(vue app)的一些總結(jié) 項(xiàng)目地址 https://github.com/BYChoo/record 項(xiàng)目簡介 此項(xiàng)目名叫:Record。是以...

    since1986 評論0 收藏0
  • 關(guān)于個(gè)人開源項(xiàng)目(vue app)的一些總結(jié)

    摘要:關(guān)于個(gè)人開源項(xiàng)目的一些總結(jié)項(xiàng)目地址項(xiàng)目簡介此項(xiàng)目名叫。網(wǎng)站目前實(shí)現(xiàn)了登錄注冊日歷導(dǎo)入文件考勤導(dǎo)出缺勤名單等核心功能。這對于小型項(xiàng)目來說并沒有什么問題。編譯后的大小關(guān)于文件上傳與導(dǎo)出功能文件上傳導(dǎo)出可以說是此項(xiàng)目最關(guān)鍵的點(diǎn)了。 關(guān)于個(gè)人開源項(xiàng)目(vue app)的一些總結(jié) 項(xiàng)目地址 https://github.com/BYChoo/record 項(xiàng)目簡介 此項(xiàng)目名叫:Record。是以...

    高勝山 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<