[nodejs] Faire des requêtes par lot, en parallèle et avec une pause

Requete par lot

Objectifs

Pouvoir Requêter en masse une API (jusqu'à 30 000 requêtes)

  • en faisant n requêtes en parallèle
  • en donnant la possibilité de créer des lots de requêtes
  • en donnant la possibilité de pouvoir pauser l'envoie des lots

Prérequis

  • nodejs
  • axios pour gérer les requêtes et l'asynchrone
  • async await pour gérer l'asynchrone

 

Le code

La vue

<div class="btn-container">
<a id="btn" class="waves-effect waves-light btn">Get all URLS</a>
</div>
<hr>

<div id="container"></div>

<pre id="result"></pre>

Le style

body {
  margin: 0;
  min-height: 100vh;
  background: #004d4d;
}
#container > div {
  width: 150px;
  margin: 10px;
  padding: 10px;
  line-height: 12px;
  background: #ededed;
  display: inline-block;
  border: 2px solid #fff;
  
  animation-name: fade-in;
	animation-fill-mode: both;
	animation-duration: .3s;
}
.teal {
  background: #008080;
}

.btn-container {
  margin: 10px;
}

.card-title {
 font-size: 14px !important; 
}

@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}


Le js

Pré-requis:
- crée un package.json en local avec npm init
- installer axios avec npm install axios --save
- coder dans votre fichier nomdefichier.js
- tester le resultat dans le terminal avec `$ node nomdefichier.js`
- tester le resultat dans le navigateur en ouvrant celui-ci

// on importe axios
const axios = require('axios');

let AllDatas = [],
    AllDatasInError = [],
    urls = [],
    waitTime = 500, // the amount of time we wait between each batch of request
    start = 0,
    step = 2, // number of url we request
    position = 0,
    nbRequest = 12; // number of request 

AllDatas['total'] = 0; // total of data

let btn = document.getElementById('btn');

btn.addEventListener('click', function() {
  batchProcessing(urls);
});

function createUrl() {
    for (let i = 1; i <= nbRequest; i++) { urls.push(`https://jsonplaceholder.typicode.com/photos/${i}`); } } createUrl(); // timer const waitFor = (ms) => new Promise(r => setTimeout(r, ms));

// parallel REQUEST with AXIOS
async function getData(links) {
    try {
        const res = await axios.all(links.map(link => axios.get(link)));
        console.log('GetData Start time', new Date());
        return res;
    } catch (error) {
        console.log('------------------------------------------');
        console.log(error);
    }
}

//
async function batchProcessing(urls) {
    const len = urls.length / step;
    // let result = [];
    console.time('batchProcessing');
    console.log('batchProcessing Start time', new Date());

    // use of an interceptor to edit every response
    axios.interceptors.response.use(function (response) {
        // Do something with response data        
        let responseData = response.data;

        // const newVal = {};
        if (responseData.id) {
          responseData['position'] = `${position}/${len}`;
            // create html element
            addElement(responseData);
          
            AllDatas['total'] += 1;
            AllDatas.push(responseData);
        }
        
        console.log('responseData', responseData);
        return responseData;
    }, function (error) {
        // Do something with response error
        return Promise.reject(error);
    });
  
  
  // batch processing

    for(let index = 0; index < len; index ++) {
      var processingUrl  = urls.slice(start, start + step);
      start += step;
      position += 1;
    
      console.log('position', position + ' / ' + len);
      console.log('processingUrl',  processingUrl);
      
      // make the requests
      const res = await getData(processingUrl);
      
      AllDatas = AllDatas.concat(res);
      // break time
      await waitFor(waitTime);
    }
    
    // we are now done
    console.log('End timer', new Date());
    console.timeEnd('getData');
    // console.log('Final AllDatas', AllDatas);
  
  // document.querySelector('pre').innerHTML = AllDatas;
}



/******
RENDERING THE HTML
*****/

function addElement (data) { 
console.log('element added', data);
let mainDiv = document.getElementById("container"); 
let newDiv = document.createElement("div");

let newContent = `
<div class="card">
<div class="card-image">
<img src="${data.thumbnailUrl}">
<span class="card-title">
Element ${data.id} 
</span>
</div>
<div class="card-content">
<p>${data.title}. (batch ${data.position})</p>
</div>
<div class="card-action">
<a href="${data.url}">See the source</a>
</div>
</div>`;


// console.log('newContent', newContent);
newDiv.innerHTML = newContent; 
mainDiv.appendChild(newDiv); 
}