Maison > interface Web > js tutoriel > le corps du texte

Schéma itératif pour adapter les abstractions JavaScript

小云云
Libérer: 2017-12-08 14:03:05
original
1575 Les gens l'ont consulté

Dans cet article, nous vous présentons le plan itératif d'ajustement de l'abstraction JavaScript, en espérant vous aider. Pour illustrer plus clairement, supposons que l'abstraction dans JavaScript est un module.

La mise en œuvre initiale d'un module n'est que le début de son long (et peut-être de longue durée) processus de cycle de vie. Je divise le cycle de vie d'un module en 3 étapes importantes.

  1. Présentation des modules. Écrivez le module ou réutilisez le module dans le projet

  2. Ajustez le module. Ajustez les modules à tout moment ;

  3. Supprimez les modules.

Dans mon article précédent, l'accent était mis sur le premier point. Et dans cet article, je me concentrerai sur le deuxième point.

Les changements de modules sont un problème que je rencontre souvent. Par rapport à l'introduction de modules, la manière dont les développeurs maintiennent et modifient les modules est tout aussi importante, voire plus, pour garantir la maintenabilité et l'évolutivité du projet. J'ai vu un module bien écrit et bien résumé être complètement ruiné après plusieurs changements au fil du temps. Je suis moi-même souvent l’un des responsables de ce changement dommageable.

Quand je dis destructif, j'entends destructeur en termes de maintenabilité et d'évolutivité. Je comprends également que face à la pression des délais d'un projet, ralentir pour apporter de meilleures révisions à la conception n'est pas une priorité.

Il peut y avoir de nombreuses raisons pour lesquelles les développeurs effectuent des modifications non optimales. Je voudrais en souligner une en particulier ici :

Conseils pour apporter des modifications de manière maintenable

Ceci. Cette approche rend vos modifications plus professionnelles.

Commençons par un exemple de code pour le module API. J'ai choisi cet exemple car communiquer avec des API externes est l'une des abstractions les plus basiques que j'ai définies au démarrage du projet. L'idée ici est de stocker toutes les configurations et paramètres associés API (comme les URL de base, la logique de gestion des erreurs, etc.) dans ce module

J'écrirai un paramètre API.url, une méthode privée. API._handleError() et une méthode publique 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);
      });
  }
};
Copier après la connexion

Dans ce module, la méthode publique API.get() renvoie un Promise. Nous utilisons notre module abstrait API au lieu d'appeler window.fetch() directement via Fetch API. Par exemple, obtenez des informations sur l'utilisateur API.get('user') ou les prévisions météorologiques actuelles API.get('weather'). La chose importante dans la mise en œuvre de cette fonctionnalité est que l'API Fetch n'est pas étroitement couplée à notre code.

Maintenant, nous sommes confrontés à une modification ! Le directeur technique nous a demandé de basculer la méthode d'obtention des données à distance vers Axios. Comment devons-nous réagir ?

Avant de commencer à discuter des méthodes, résumons ce qui est inchangé et ce qui doit être modifié :

  1. Modifications : en public API.get() méthode Dans

  • vous devez modifier l'appel axios() de window.fetch() ; vous devez à nouveau renvoyer un Promise pour garder l'interface cohérente. Heureusement, Axios est basé sur Promise. Oui, super !

  • Le serveur a répondu avec JSON. Analysez les données de réponse via Fetch API et en enchaînant les instructions .then( res => res.json()). Avec Axios, la réponse du serveur est dans l'attribut data et nous n'avons pas besoin de l'analyser. Par conséquent, nous devons remplacer l'instruction .then par .then(res => res.data).

  • Modification : En privé API._handleError méthode :

    • Indicateur booléen ok manquant dans l'objet de réponse, cependant , il y a aussi l'attribut statusText. Nous pouvons l'enchaîner, et si sa valeur est OK, alors tout ira bien (remarque : Fetch API dans OK est true et Axios dans statusText est OK est différent. Mais pour faciliter la compréhension et ne pas être trop large, aucune gestion avancée des erreurs n'est introduite)

  • Restez inchangé : API.url les changements, nous détectons les erreurs et les rappelons de manière agréable chemin.

  • Explication terminée ! Passons maintenant à la méthode réelle d’application de ces modifications.

    Méthode 1 : Supprimer le code. Écrivez du code.

    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 => res.json())
              .then( res => res.data)
              .catch( error => {
                  alert('So sad. There was an error.');
                  throw new Error(error);
              });
      }
    };
    Copier après la connexion

    Cela semble raisonnable. Soumettez, téléchargez, fusionnez, complétez.

    Cependant, dans certains cas, cela peut ne pas être une bonne idée. Imaginez le scénario suivant : après être passé à Axios, vous découvrez qu'il existe une fonctionnalité qui ne fonctionne pas avec XMLHttpRequests (la méthode d'obtention de données de Axios), mais les navigateurs les plus récents qui utilisaient Fetch API fonctionnaient auparavant très bien. . Que devons-nous faire maintenant ?

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

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

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

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

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

    如下所示:
    Schéma itératif pour adapter les abstractions 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());
      }
    };
    Copier après la connexion

    步骤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);
          });
      }
    };
    Copier après la connexion

    现在情况不一样了!这种结构能让你处理各种不同的获取数据的场景(适配器)改。最后一步,你猜对了!写一个 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);
      }
    };
    Copier après la connexion

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

    class API {
      constructor(_adapter = new /*FetchAdapter()*/ AxiosAdapter()) {
        this.adapter = _adapter;
    
        /* ... */
      }
      /* ... */
    };
    Copier après la connexion

    真棒!如果我们需要在这个特定的用例中使用旧的 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');
    Copier après la connexion

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

    • 删除代码,编写代码。

    • 重构代码,写适配器。

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

    相关推荐:

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

    JavaScript中filter函数的详细介绍

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

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Étiquettes associées:
    source:php.cn
    Déclaration de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
    Tutoriels populaires
    Plus>
    Derniers téléchargements
    Plus>
    effets Web
    Code source du site Web
    Matériel du site Web
    Modèle frontal