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.
Présentation des modules. Écrivez le module ou réutilisez le module dans le projet
Ajustez le module. Ajustez les modules à tout moment ;
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 :
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); }); } };
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é :
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.
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); }); } };
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!???对于那些熟悉适配器模式(也被称为包装模式)的人来说,是的,那正是我们前进的方向!如果您对所有的细节感兴趣,请参阅这里我的介绍。
如下所示:
将跟 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()); } };
重构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');
所以下次你需要改变你的项目时,评估下面哪种方法更有意义:
删除代码,编写代码。
重构代码,写适配器。
总结请根据你的场景选择性使用。如果你的代码库滥用适配器和引入太多的抽象可能会导致复杂性增加,这也是不好的。愉快的去使用适配器吧!
相关推荐:
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!