Maison  >  Article  >  interface Web  >  Analyse du code source Axios comment implémenter une bibliothèque de requêtes HTTP

Analyse du code source Axios comment implémenter une bibliothèque de requêtes HTTP

不言
不言original
2018-07-25 10:15:511524parcourir

Le contenu partagé avec vous dans cet article explique comment implémenter une bibliothèque de requêtes HTTP via l'analyse du code source axios. Le contenu est très détaillé. Examinons ensuite le contenu spécifique. J'espère que cela pourra aider tout le monde.

Aperçu

Au cours du processus de développement front-end, nous rencontrons souvent des situations où nous devons envoyer des requêtes asynchrones. L'utilisation d'une bibliothèque de requêtes HTTP avec des fonctions complètes et des interfaces complètes peut réduire considérablement nos coûts de développement et améliorer notre efficacité de développement.

axios est une bibliothèque de requêtes HTTP devenue très populaire ces dernières années. Elle compte actuellement plus de 40 000 étoiles dans GitHub et a été recommandée par tout le monde.

Aujourd'hui, nous allons examiner comment axios est conçu et ce qui vaut la peine d'en tirer des leçons. Lorsque j'ai écrit cet article, la version d'axios était 0.18.0. Prenons cette version du code comme exemple pour effectuer une lecture et une analyse spécifiques du code source. Actuellement, tous les fichiers de code source d'axios se trouvent dans le dossier lib, donc les chemins que nous mentionnons ci-dessous font référence aux chemins du dossier lib.

Le contenu principal de cet article est :

  • Comment utiliser axios

  • Comment le module de base d'axios est conçu et mis en œuvre (Demandes, intercepteurs, retraits)

  • Ce qui vaut la peine d'être appris de la conception d'axios

Comment utiliser axios

Comment utiliser axios

Pour comprendre la conception d'axios, nous devons d'abord regarder comment axios est utilisé. Nous présentons l'API axios suivante à travers un exemple simple.
axios({
  method:'get',
  url:'http://bit.ly/2mTM3nY',
  responseType:'stream'
})
  .then(function(response) {
  response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});

Envoyer la demande

Ceci est un exemple d'API officiel. À partir du code ci-dessus, nous pouvons voir que l'utilisation d'axios est très similaire à l'ajax de jQuery, qui continuent tous deux les opérations ultérieures en renvoyant une promesse (vous pouvez également utiliser le rappel de réussite, mais il est recommandé d'utiliser Promise ou wait).

Cet exemple de code est très simple, je n'entrerai donc pas dans les détails. Voyons comment ajouter une fonction de filtre.
// 增加一个请求拦截器,注意是2个函数,一个处理成功,一个处理失败,后面会说明这种情况的原因
axios.interceptors.request.use(function (config) {
    // 请求发送前处理
    return config;
  }, function (error) {
    // 请求错误后处理
    return Promise.reject(error);
  });

// 增加一个响应拦截器
axios.interceptors.response.use(function (response) {
    // 针对响应数据进行处理
    return response;
  }, function (error) {
    // 响应错误后处理
    return Promise.reject(error);
  });

Ajouter une fonction d'intercepteurs

À partir de l'exemple ci-dessus, nous pouvons savoir : avant l'envoi de la requête, nous pouvons effectuer des données sur les paramètres de configuration du traitement de la requête ; et après avoir demandé une réponse, nous pouvons également effectuer des opérations spécifiques sur les données renvoyées. Dans le même temps, nous pouvons effectuer une gestion spécifique des erreurs lorsque la demande échoue et que la réponse échoue.

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
Annuler la demande HTTP

Lors de l'exécution de fonctions liées à la recherche, nous devons souvent envoyer des demandes fréquentes de requête de données. De manière générale, lorsque nous envoyons la prochaine demande, nous devons annuler la demande précédente. Par conséquent, la fonctionnalité liée à l’annulation des demandes est également un plus. L'exemple de code pour la demande d'annulation d'axios est le suivant :

Grâce à l'exemple ci-dessus, nous pouvons voir qu'axios utilise une proposition de retrait basée sur CancelToken. Cependant, la proposition a maintenant été retirée. Les détails peuvent être trouvés ici. Nous expliquerons la méthode spécifique de mise en œuvre du retrait dans l'analyse du code source dans les chapitres suivants.

Comment le module de base d'axios est conçu et implémenté

Grâce aux exemples ci-dessus, je pense que tout le monde a une compréhension générale de la façon d'utiliser axios. Ensuite, nous analyserons la conception et la mise en œuvre d'axios selon les modules. L'image ci-dessous montre les fichiers axios pertinents que nous aborderons dans ce blog. Si les lecteurs sont intéressés, ils peuvent les lire via le code associé au clone et le blog, ce qui peut approfondir leur compréhension des modules concernés.

core/dispatchReqeust.js

Module de requête HTTP
module.exports = function dispatchRequest(config) {
    throwIfCancellationRequested(config);

    // 其他源码

    // default adapter是一个可以判断当前环境来选择使用Node还是XHR进行请求发送的模块
    var adapter = config.adapter || defaults.adapter; 

    return adapter(config).then(function onAdapterResolution(response) {
        throwIfCancellationRequested(config);

        // 其他源码

        return response;
    }, function onAdapterRejection(reason) {
        if (!isCancel(reason)) {
            throwIfCancellationRequested(config);

            // 其他源码

            return Promise.reject(reason);
        });
};

dispatchRequestEn tant que module de base, le code lié à l'envoi de requêtes axios se trouve dans le fichier config.adapter. En raison de l'espace limité, je sélectionnerai quelques codes sources clés pour une brève introduction ci-dessous :

default.jsGrâce au code et aux exemples ci-dessus, nous pouvons savoir que la méthode

obtient la demande d'envoi en obtenant
function getDefaultAdapter() {
    var adapter;
    // 只有Node.js才有变量类型为process的类
    if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
        // Node.js请求模块
        adapter = require('./adapters/http');
    } else if (typeof XMLHttpRequest !== 'undefined') {
        // 浏览器请求模块
        adapter = require('./adapters/xhr');
    }
    return adapter;
}
Pour les modules, on peut également remplacer le module natif en passant la fonction adaptateur conforme à la spécification (bien que cela ne soit généralement pas fait, cela peut être considéré comme un point d'extension faiblement couplé).

adapters/xhr.jsDans le fichier

, nous pouvons voir la logique de sélection de l'adaptateur pertinente, qui est basée sur certaines propriétés et constructeurs uniques au conteneur actuel.

Le module XHR dans axios est relativement simple. Il s'agit d'une encapsulation de l'objet XMLHTTPRequest. Nous ne le présenterons pas en détail ici. Les étudiants intéressés peuvent le lire par eux-mêmes. 🎜> fichier.

dispatchRequestModule intercepteur request

Axios.prototype.request = function request(config) {

    // 其他代码

    var chain = [dispatchRequest, undefined];
    var promise = Promise.resolve(config);

    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        chain.push(interceptor.fulfilled, interceptor.rejected);
    });

    while (chain.length) {
        promise = promise.then(chain.shift(), chain.shift());
    }

    return promise;
};
Après avoir compris le module d'envoi de requêtes HTTP implémenté par

, examinons comment axios gère les fonctions d'interception de requête et de réponse. Jetons un coup d'œil à la fonction d'entrée unifiée

demandée dans axios. Cette fonction est le point d'entrée permettant à axios d'envoyer des requêtes. Parce que la mise en œuvre de la fonction est relativement longue, je vais brièvement parler des idées de conception pertinentes : .
  1. chain是一个执行队列。这个队列的初始值,是一个带有config参数的Promise。

  2. 在chain执行队列中,插入了初始的发送请求的函数dispatchReqeust和与之对应的undefined。后面需要增加一个undefined是因为在Promise中,需要一个success和一个fail的回调函数,这个从代码promise = promise.then(chain.shift(), chain.shift());就能够看出来。因此,dispatchReqeustundefined我们可以成为一对函数。

  3. 在chain执行队列中,发送请求的函数dispatchReqeust是处于中间的位置。它的前面是请求拦截器,通过unshift方法放入;它的后面是响应拦截器,通过push放入。要注意的是,这些函数都是成对的放入,也就是一次放入两个。

通过上面的request代码,我们大致知道了拦截器的使用方法。接下来,我们来看下如何取消一个HTTP请求。

取消请求模块

取消请求相关的模块在Cancel/文件夹中。让我们来看下相关的重点代码。

首先,让我们来看下元数据Cancel类。它是用来记录取消状态一个类,具体代码如下:

    function Cancel(message) {
      this.message = message;
    }

    Cancel.prototype.toString = function toString() {
      return 'Cancel' + (this.message ? ': ' + this.message : '');
    };

    Cancel.prototype.__CANCEL__ = true;

而在CancelToken类中,它通过传递一个Promise的方法来实现了HTTP请求取消,然我们看下具体的代码:

function CancelToken(executor) {
    if (typeof executor !== 'function') {
        throw new TypeError('executor must be a function.');
    }

    var resolvePromise;
    this.promise = new Promise(function promiseExecutor(resolve) {
        resolvePromise = resolve;
    });

    var token = this;
    executor(function cancel(message) {
        if (token.reason) {
            // Cancellation has already been requested
            return;
        }

        token.reason = new Cancel(message);
        resolvePromise(token.reason);
    });
}

CancelToken.source = function source() {
    var cancel;
    var token = new CancelToken(function executor(c) {
        cancel = c;
    });
    return {
        token: token,
        cancel: cancel
    };
};

而在adapter/xhr.js文件中,有与之相对应的取消请求的代码:

if (config.cancelToken) {
    // 等待取消
    config.cancelToken.promise.then(function onCanceled(cancel) {
        if (!request) {
            return;
        }

        request.abort();
        reject(cancel);
        // 重置请求
        request = null;
    });
}

结合上面的取消HTTP请求的示例和这些代码,我们来简单说下相关的实现逻辑:

  1. 在可能需要取消的请求中,我们初始化时调用了source方法,这个方法返回了一个CancelToken类的实例A和一个函数cancel。

  2. 在source方法返回实例A中,初始化了一个在pending状态的promise。我们将整个实例A传递给axios后,这个promise被用于做取消请求的触发器。

  3. 当source方法返回的cancel方法被调用时,实例A中的promise状态由pending变成了fulfilled,立刻触发了then的回调函数,从而触发了axios的取消逻辑——request.abort()

axios的设计有什么值得借鉴的地方

发送请求函数的处理逻辑

在之前的章节中有提到过,axios在处理发送请求的dispatchRequest函数时,没有当做一个特殊的函数来对待,而是采用一视同仁的方法,将其放在队列的中间位置,从而保证了队列处理的一致性,提高了代码的可阅读性。

Adapter的处理逻辑

在adapter的处理逻辑中,axios没有把http和xhr两个模块(一个用于Node.js发送请求,另一个则用于浏览器端发送请求)当成自身的模块直接在dispatchRequest中直接饮用,而是通过配置的方法在default.js文件中进行默认引入。这样既保证了两个模块间的低耦合性,同时又能够为今后用户需要自定义请求发送模块保留了余地。

取消HTTP请求的处理逻辑

在取消HTTP请求的逻辑中,axios巧妙的使用了一个Promise来作为触发器,将resolve函数通过callback中参数的形式传递到了外部。这样既能够保证内部逻辑的连贯性,也能够保证在需要进行取消请求时,不需要直接进行相关类的示例数据改动,最大程度上避免了侵入其他的模块。

总结

本文对axios相关的使用方式、设计思路和实现方法进行了详细的介绍。读者能够通过上述文章,了解axios的设计思想,同时能够在axios的代码中,学习到关于模块封装和交互等相关的经验。

由于篇幅原因,本文仅针对axios的核心模块进行了分解和介绍,如果对其他代码有兴趣的同学,可以去GitHub进行查看。

相关推荐:

React组件中绑定this的原因分析

angularjs关于页面模板清除的使用方法

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!

Déclaration:
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