首頁  >  文章  >  web前端  >  調整JavaScript抽象的迭代方案

調整JavaScript抽象的迭代方案

小云云
小云云原創
2017-12-08 14:03:051566瀏覽

本文我們跟大家介紹調整JavaScript抽象的迭代方案,希望能幫助大家。為了更清楚的說明,我們假設在 JavaScript 中抽像是一個模組。

一個模組的最初實現只是它們漫長(也許是持久的)的生命週期過程的開始。我將一個模組的生命週期分成 3 個重要階段。

  1. 引入模組。在專案中編寫該模組或複用該模組;

  2. #調整模組。隨時調整模組;

  3. 移除模組。

在我先前的文章中,重心放在了第一點。而在這篇文章中,我將把重點放在第二點上。

模組更改是我經常碰到的難題。與引入模組相比,開發者維護和更改模組的方式對確保專案的可維護性和可拓展性是同等重要甚至更重要。我看過一個寫得很好、抽象得很好的模組隨著時間推移歷經多次更改後被徹底毀了。我自己也常常是造成那種破壞性改變的其中一個。

當我說破壞性,我指的是對可維護性和可擴展性方面的破壞。我也明白,當面臨專案最後交付期限的壓力時,放慢速度以進行更好的修改設計並不是優先選擇。

開發者做出非最優修改的原因可能有很多種,我在這裡想特別強調一個:

#以可維護的方式進行修改的技巧

#這種方法讓你的修改顯得更專業。

讓我們從一個 API 模組的程式碼範例開始。之所以選擇這個範例,是因為與外部 API 通訊是我在開始專案時定義的最基本的抽象之一。這裡的想法是將所有與API 相關的配置和設定(如基本URL,錯誤處理邏輯等)儲存在這個模組中.

#我將編寫一個設定API.url、一個私有方法API._handleError() 和一個公共方法 API.get():

class API {
  constructor() {
    this.url = 'http://whatever.api/v1/';
  }

  /**
   * API 数据获取的特有方法
   * 检查一个 HTTP 返回的状态码是否在成功的范围内
   */
  _handleError(_res) {
    return _res.ok ? _res : Promise.reject(_res.statusText);
  }

  /**
   * 获取数据
   * @return {Promise}
   */
  get(_endpoint) {
    return window.fetch(this.url + _endpoint, { method: 'GET' })
      .then(this._handleError)
      .then( res => res.json())
      .catch( error => {
        alert('So sad. There was an error.');
        throw new Error(error);
      });
  }
};

在在這個模組中,公共方法API.get() 傳回一個Promise。我們使用我們抽象的 API模組,而不是透過 window.fetch() 直接呼叫 Fetch API 。例如,取得使用者資訊 API.get('user')或目前天氣預報 API.get('weather')。實現這個功能的重要意義在於Fetch API與我們的程式碼沒有緊密耦合。

現在,我們面臨一個修改!技術主管要求我們把取得遠端資料的方式切換到Axios。我們該如何應對呢?

在我們開始討論方法之前,我們先來總結一下什麼是不變的,什麼是需要修改的:

  1. 更改:在公共API .get() 方法中

  • 需要修改axios()window.fetch()呼叫;需要再次返回一個Promise,以保持介面的一致, 好在Axios 是基於Promise 的,太棒了!

  • 伺服器的回應的是 JSON。透過 Fetch API 並透過鍊式呼叫 .then( res => res.json()) 語句來解析回應的資料。使用 Axios,伺服器回應是在 data 屬性中,我們不需要解析它。因此,我們需要將.then語句改為.then(res => res.data)

  • 更改:在私有API._handleError 方法:

    • ##在回應物件中缺少

      ok 布林標誌,但是,還有statusText 屬性。我們可以透過它來串起來,如果它的值是OK,那麼一切將沒什麼問題(附註:在Fetch APIOK# 為 true 與在Axios 中的statusTextOK 是不一樣的。錯誤處理。

    講解完畢!現在讓我們深入應用這些修改的實際方法。
  • 方法一:刪除程式碼。編寫程式碼。 <pre class="brush:php;toolbar:false">class API {   constructor() {     this.url = 'http://whatever.api/v1/'; // 一模一样的   }   _handleError(_res) {       // DELETE: return _res.ok ? _res : Promise.reject(_res.statusText);       return _res.statusText === 'OK' ? _res : Promise.reject(_res.statusText);   }   get(_endpoint) {       // DELETE: return window.fetch(this.url + _endpoint, { method: 'GET' })       return axios.get(this.url + _endpoint)           .then(this._handleError)           // DELETE: .then( res =&gt; res.json())           .then( res =&gt; res.data)           .catch( error =&gt; {               alert('So sad. There was an error.');               throw new Error(error);           });   } };</pre>聽起來很合理。 提交、上傳、合併、完成。

  • 不過,在某些情況下,這可能不是一個好主意。想像以下情境:在切換到Axios

    之後,你會發現有一個功能並不適用於XMLHttpRequests(

    Axios

    的取得資料的方法),但之前使用

    Fetch API

    的新型瀏覽器運作得很好。我們現在該怎麼辦?

    我们的技术负责人说,让我们使用旧的 API 实现这个特定的用例,并继续在其他地方使用 Axios 。你该做什么?在源代码管理历史记录中找到旧的 API 模块。还原。在这里和那里添加 if 语句。这样听起来并不太友好。

    必须有一个更容易,更易于维护和可扩展的方式来进行更改!那么,下面的就是。

    方法二:重构代码,做适配!

    重构的需求马上来了!让我们重新开始,我们不再删除代码,而是让我们在另一个抽象中移动 Fetch 的特定逻辑,这将作为所有 Fetch 特定的适配器(或包装器)。

    HEY!???对于那些熟悉适配器模式(也被称为包装模式)的人来说,是的,那正是我们前进的方向!如果您对所有的细节感兴趣,请参阅这里我的介绍。

    如下所示:
    調整JavaScript抽象的迭代方案

    步骤1

    将跟 Fetch 相关的几行代码拿出来,单独抽象为一个新的方法 FetchAdapter

    class FetchAdapter {
      _handleError(_res) {
        return _res.ok ? _res : Promise.reject(_res.statusText);
      }
    
      get(_endpoint) {
        return window.fetch(_endpoint, { method: 'GET' })
          .then(this._handleError)
          .then( res => res.json());
      }
    };

    步骤2

    重构API模块,删除 Fetch 相关代码,其余代码保持不变。添加 FetchAdapter 作为依赖(以某种方式):

    class API {
      constructor(_adapter = new FetchAdapter()) {
        this.adapter = _adapter;
    
        this.url = 'http://whatever.api/v1/';
      }
    
      get(_endpoint) {
        return this.adapter.get(_endpoint)
          .catch( error => {
            alert('So sad. There was an error.');
            throw new Error(error);
          });
      }
    };

    现在情况不一样了!这种结构能让你处理各种不同的获取数据的场景(适配器)改。最后一步,你猜对了!写一个 AxiosAdapter

    const AxiosAdapter = {
      _handleError(_res) {
        return _res.statusText === 'OK' ? _res : Promise.reject(_res.statusText);
      },
    
      get(_endpoint) {
        return axios.get(_endpoint)
          then(this._handleError)
          .then( res => res.data);
      }
    };

    API 模块中,将默认适配器改为 AxiosAdapter

    class API {
      constructor(_adapter = new /*FetchAdapter()*/ AxiosAdapter()) {
        this.adapter = _adapter;
    
        /* ... */
      }
      /* ... */
    };

    真棒!如果我们需要在这个特定的用例中使用旧的 API 实现,并且在其他地方继续使用Axios?没问题!

    //不管你喜欢与否,将其导入你的模块,因为这只是一个例子。
    import API from './API';
    import FetchAdapter from './FetchAdapter';
    
    //使用 AxiosAdapter(默认的)
    const API = new API();
    API.get('user');
    
    
    // 使用FetchAdapter
    const legacyAPI = new API(new FetchAdapter());
    legacyAPI.get('user');

    所以下次你需要改变你的项目时,评估下面哪种方法更有意义:

    • 删除代码,编写代码。

    • 重构代码,写适配器。

    总结请根据你的场景选择性使用。如果你的代码库滥用适配器和引入太多的抽象可能会导致复杂性增加,这也是不好的。愉快的去使用适配器吧!

    相关推荐:

    JavaScript工作体系中不可或缺的函数

    JavaScript中filter函数的详细介绍

    JS实现的计数排序与基数排序算法示例_javascript技巧

    以上是調整JavaScript抽象的迭代方案的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn