Узел js, как запускать axios.get каждые 2 секунды? - PullRequest
1 голос
/ 03 июля 2019

Я новичок в узле js, вот что я пытаюсь сделать: я перебираю json-файл, полный ссылок нашего сайта через функцию карты (около 3000 ссылок), внутри цикла я нахожусьвыполнение аксиоса get для каждой ссылки и получение кода состояния ответа (в будущем будут выполняться другие действия).Но я хочу, чтобы запускать аксиос получался только каждые 2 или 5 секунд, иначе я перегружаю веб-сервер.Я пытаюсь ввести асинхронное ожидание, но оно все еще слишком быстрое, и сервер получает удар (технически я делаю свой собственный сайт).Я поместил SetTimeout вокруг осей, но это не похоже на работу, так как в консоли результаты печатаются слишком быстро. поэтому вопрос в том, как заставить каждый запрос axios.get ждать каждые 2 секунды перед запуском в цикле карты?.

var axios = require('axios');
const fs = require('fs');
var statusCheck = 0;

var main = [];
let rawdata = fs.readFileSync('C:/Users/jay/Documents/crawl/filtered2.json');
let jsonParsed = JSON.parse(rawdata);

jsonParsed.map(async(line) => {

    var encodeLink = encodeURI(line.link);
    const response = await axios.get(encodeLink).catch((err) => {
        var Status_ErrorsCatchaxios = {
            "status Code": err.response.status ? err.response.status : "No status code available",
            "Page title:": $('title').text() ? $('title').text() : 'No title avaialble',
            "Original Link": encodeLink ? encodeLink : "No Original Link Available",
            "errorCode": err
        }
        main.push(Status_ErrorsCatchaxios)
    })
    try {
        console.log(response.status)

        statusCheck = statusCheck + 1;
        console.log("Link: ", statusCheck)
    } catch (error) {
        console.log(error)
    }
})

Ответы [ 5 ]

1 голос
/ 03 июля 2019

Причина, по которой тайм-аут не работает в цикле, заключается в том, что он запускает все запросы / функции сразу после задержки timeout.

Идея состоит в том, чтобы ставить задержку в каждой итерации и только после задержки начинать следующую итерацию.

Вы можете запустить функцию самозапуска, которая вызывает себя после задержки.Таким образом, чтобы запускать функцию каждые 2 секунды, вы можете попробовать это:

let jsonParsed = JSON.parse(rawdata);
let len = jsonParsed.length;

(function requestLoop (i) {          
    setTimeout(function () {   
        let line = jsonParsed[len-i]
        var encodeLink = encodeURI(line.link);
        const response = await axios.get(encodeLink).catch((err) => {
            var Status_ErrorsCatchaxios = {
                "status Code": err.response.status ? err.response.status : "No status code available",
                "Page title:": $('title').text() ? $('title').text() : 'No title avaialble',
                "Original Link": encodeLink ? encodeLink : "No Original Link Available",
                "errorCode": err
            }
            main.push(Status_ErrorsCatchaxios)
        })
        try {
            console.log(response.status)

            statusCheck = statusCheck + 1;
            console.log("Link: ", statusCheck)
        } catch (error) {
            console.log(error)
        }                        
        let jsonParsed = JSON.parse(rawdata);

        if (--i) requestLoop(i);     
   }, 2000)
})(len);
1 голос
/ 03 июля 2019

Вы бьете все сразу, потому что .map, .forEach, .reduce и т. Д. Не ждут разрешения Promise.Используйте цикл Simple For, он будет ожидать разрешения или отклонения каждого обещания.

for(let i=0;i<jsonParsed.length;i++) {
    var encodeLink = encodeURI(line.link);
    const response = await axios.get(encodeLink).catch(...)
    try {
        ....
    } catch (error) {
        ...
    }
})

Почему это не работает?Если мы имитируем цикл forEach, это будет что-то вроде

function forEach(arr, cb){
    for(let i=0;i<arr.length;i++){
        cb(arr[i], i, cb);
    }
}

Так что вы видите, что это не await cb.

1 голос
/ 03 июля 2019

Функция [].map не ожидает разрешения ваших элементов, поэтому ваш код в настоящее время отправляет все запросы (как вы сказали, около 3000) параллельно.

Вы можете использовать for...of вместо того, чтобы запускать только один запрос за раз.Например:

async function makeRequests (lines) {
  for (const line of lines) {
    const encodedLink = encodeURI(line.link)
    const response = await axios.get(encodedLink)
    // ...your response handling code here...
  }
}

makeRequests(jsonParsed)

Если вы хотите подождать 2 секунды между каждым запросом, вы можете добавить эту строку кода в ваш цикл for...of:

await new Promise(resolve => setTimeout(resolve, 2000))

Лучшее решение

Решение, приведенное выше, работает, но я предполагаю, что ваш веб-сервер может, вероятно, принимать более одного запроса за раз, поэтому, возможно, идеальным сценарием было бы ограничить ваш код, чтобы он выполнял только до N запросов впараллельно в данный момент времени.Таким образом, вы не заполняете свой сервер, но можете получать результаты быстрее, чем один запрос за раз.

Модуль bluebird NPM позволяет вам делать это с помощьюих функция Promise.map .

Эта функция получает ваш список элементов в качестве первого аргумента, функцию, которая выполняет что-то и возвращает обещание для каждого элемента в качестве второго аргумента, и объектс ключом concurrency, описывающим, сколько элементов вы хотите разрешить обрабатывать параллельно в качестве третьего аргумента.

Вот как это может работать:

const bluebird = require('bluebird')

async function makeRequests (lines) {
  await bluebird.map(
    lines,
    async (line) => {
      const encodedLink = encodeURI(line.link)
      const response = await axios.get(encodedLink)
      // ...your response handling code here...
    },
    { concurrency: 3 }
  )
}

makeRequests(jsonParsed)
1 голос
/ 03 июля 2019

Откажитесь от map, замените на for ... of, дождитесь обещания, для решения которого требуется 2 секунды, оберните все внутри асинхронного IIFE, чтобы ожидание было законным.

// dummy data
const fakeJson = new Array(5).fill();
const fakeRequest = () => console.log(`request at ${new Date().toUTCString()}`);

// iteration with 2s in between
(async () => {
  for (let line of fakeJson) {
    await new Promise(r => setTimeout(r, 2000));
    fakeRequest();
  }
})()

Вы также можете использовать более классически setInterval , но HTTP-запросы асинхронны, поэтому могут также начинаться со структуры, которая хорошо обрабатывает асинхронные циклы и циклы.

0 голосов
/ 03 июля 2019

Вы можете использовать функцию setTimeout для запуска кодов каждые 2 секунды!

setTimeout(async() => {
 // await postRequest()
},2000)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...