Как запустить запрос последовательно в цикле? - PullRequest
0 голосов
/ 11 декабря 2018

Это псевдокод того, чего я пытаюсь достичь.Сначала мне нужно получить список URL-адресов из тела запроса, затем передать эти URL-адреса в функцию запроса (используя модуль запроса), которая будет получать данные из каждого URL-адреса, а затем сохранять эти данные в MongoDB.После того, как все запросы завершены, включая сохранение данных на сервер только тогда, он должен отправить ответ.

app.post('/', (req, resp) => {

    const { urls } = req.body;

    urls.forEach((url, i) => {

        request(url, function (err, resp, body) {

            if (err) {
                console.log('Error: ', err)
            } else {
                // function to save data to MongoDB server
               saveUrlData(body);
               console.log(`Data saved for URL number - ${i+1}`)
            }
        })
    });

    // Should be called after all data saved from for loop
    resp.send('All data saved')
})

Я попробовал этот код, и, конечно, функция resp.send () будет работать без заботы, еслизапрос выполненИспользуя этот код, я получаю на консоли такой результат:

Data saved for URL number - 3
Data saved for URL number - 1
Data saved for URL number - 5
Data saved for URL number - 2
Data saved for URL number - 4

Я мог бы написать их во вложенной форме, но переменная urls может иметь любое количество URL-адресов, и поэтому она должна быть впо крайней мере, из моего понимания.Я хочу, чтобы запросы выполнялись последовательно, то есть он должен разрешать 1-й URL, а затем второй и т. Д., И когда все URL-адреса выполняются только тогда, он должен ответить.Пожалуйста, помогите!

Ответы [ 5 ]

0 голосов
/ 11 декабря 2018

Есть несколько способов решить эту проблему.

  • вы можете использовать async/await

  • Обещания

  • вы также можете использовать асинхронную библиотеку

    app.post('/', (req, res, next) => {
        const { urls } = req.body;
    
        async.each(urls, get_n_save, err => {
            if (err) return next(err);
            res.send('All data saved');
        });
    
        function get_n_save (url, callback) {
            request(url, (err, resp, body) => {
                if (err) {
                    return callback(err);
                }
                saveUrlData(body);
                callback();
            });
        }
    });
    
0 голосов
/ 11 декабря 2018

Глядя на намерение (сканер), вы можете использовать Promise.all, поскольку URL-адреса не зависят друг от друга.

app.post('/', (req, resp) => {

    const { urls } = req.body;

    const promises = urls.map((url, i) => {
        return new Promise((resolve, rej)=>{
            request(url, function (err, resp, body) {
                if (err) {
                    rej(err);
                } else {
                   resolve(body);
                }
            })
        })
        .then((body)=>{
            //this should definitely be a promise as you are saving data to mongo
            return saveUrlData(body);
        })
    });

    // Should be called after all data saved from for loop
    Promise.all(promises).then(()=>resp.send('All data saved'));
})

Примечание. Необходимо также выполнять обработку ошибок.

0 голосов
/ 11 декабря 2018
app.post('/', async (req, resp) => {

    const {
        urls
    } = req.body;

    for (const url of urls) {
        try {
            const result = await doRequest(url)
            console.log(result)

        } catch (error) {
            // do error processing here 
            console.log('Error: ', err)
        }
    }
})

function doRequest(url) {
    return new Promise((resolve, reject) => {
        request(url, function(err, resp, body) {
            err ? reject(err) ? resolve(body)
        })    
    })    
}

с использованием асинхронное ожидание

0 голосов
/ 11 декабря 2018

Вы хотите подождать, пока все ответы API не будут получены и сохранены в БД, поэтому вы должны выполнить async-await и обещать все ответы.Вы можете использовать модуль Request-Promise вместо запроса.Таким образом, вы получите обещание на каждый запрошенный вызов API вместо обратного вызова.И используйте promise для вызова всех запросов (модулей) внутри массива.Используя async-await, выполнение вашего кода будет ждать, пока все вызовы API не получат ответ и не сохранятся в БД.

const rp = require('request-promise');
app.post('/', async (req, res) => {
  try{
   const { urls } = req.body;
    // completed all will have all the api resonse. 
    const completedAll = await sendRequest(urls);
    // now we have all api response that needs to be saved
    // completedAll is array
    const saved = await saveAllData(completedAll);
    // Should be called after all data saved from for loop
    res.status(200).send('All data saved')
  }
  catch(err) {
   res.status(500).send({msg: Internal_server_error})
 }
})

function sendRequest(urlArr, i){
    const apiCalls = [];
    for(let i=0;i < urlArr.length; i++){
      apiCalls.push(rp(urlArr[i]));
    }
    // promise.all will give all api response in order as we pushed api call
    return Promise.all(apiCalls);
}

Вы можете обратиться по этим ссылкам: https://www.npmjs.com/package/request-promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

0 голосов
/ 11 декабря 2018

Вы должны посмотреть на Обещания JavaScript

В противном случае вы можете сделать рекурсивный запрос следующим образом:

app.post('/', (req, resp) => {

    const { urls } = req.body;

    sendRequest(urls, 0);
})

function sendRequest(urlArr, i){

    request(urlArr[i], function (err, resp, body) {
      if (err) {
           console.log('Error: ', err)
      }
      else {
           saveUrlData(body);
           console.log(`Data saved for URL number - ${i+1}`)
      }

      i++;
      if(i == urlArr.length) resp.send('All data saved') //finish
      else sendRequest(urlArr, i); //send another request
   })
}

Все, что мне нужно было сделать, это создать отдельноефункцию, которую я могу вызывать снова и снова, передавая массив url и базовый индекс 0 в качестве аргументов.Каждый успешный обратный вызов увеличивает индексную переменную, которую я снова передаю в той же функции.Промойте и повторяйте, пока мой индекс не достигнет длины массива url, я остановлю рекурсивный цикл оттуда.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...