Nano Hash - криптовалюты, майнинг, программирование

Получение разбитого на страницы списка элементов из API

Мне нужно получить список элементов из конечной точки API (/products), но они разбиты на страницы (максимум 200 элементов на странице).

Мне нужно сделать цикл, который получит 200 продуктов, переместит их в массив и увеличит номер страницы, чтобы он мог запросить еще 200 продуктов. Он остановится, когда появится ошибка 404 (страница не существует), что означает, что я получил все продукты.

Я использую Axios для запросов, основанных на обещаниях, но я не могу заставить его работать. Я пробовал несколько вещей, даже создавая свои собственные промисы, но результаты такие же:

  • Не могу заставить его ждать, пока будут запрошены все страницы
  • Он всегда будет запрашивать одну и ту же страницу, потому что приращение страницы находится внутри .then обещания (чтобы быть уверенным, что я не выйду за пределы последней страницы)

Я знаю, что идея Promises заключается в том, чтобы быть асинхронной, но я пытаюсь найти способ заставить ее работать.

Кто-нибудь знает, какую логику я мог бы использовать для этого? Я просто хочу получить все предметы, прежде чем двигаться дальше. Может быть, я слишком усложняю, некоторые разъяснения очень помогли бы.

РЕДАКТИРОВАТЬ:

Пытался сделать это рекурсивно, но результат всегда возвращается до выполнения:

module.exports = {
  sync(req, res) {
    // Get all products page by page
    var products = module.exports.getProductsByPage()
    res.status(200).send(products)
  },

  getProductsByPage(page = 1, products = []) {
    nuvemshop.get(`products?page=${page}&per_page=200`)
    .then(res => {
        console.log('GET Products PAGE ' + page)
        products.push(res.data)
        arguments.callee(++page, products)
    })
    .catch(e => {
        if(e.response.status === 404) {
            console.log('LAST PAGE REACHED')
            return products
        } else 
            return e
    })
  },

  • вы можете выполнить ту же функцию внутри блока .then и дать ей следующий URL-адрес, у меня нет API с таким количеством данных, чтобы протестировать его и привести пример кода, но я надеюсь, что вы поняли мою точку зрения 05.02.2018
  • Я пытался сделать его рекурсивным, но результат всегда возвращается перед всеми выполнениями 05.02.2018
  • Добавил пример кода 05.02.2018
  • Я собираюсь высказать несколько идей, возможно, это проблема, но я не уверен, возможно, добавьте свойство с именем products в ваш экспортируемый объект. затем в блоке .then назовите его как this.products.push.res.data 05.02.2018
  • Хорошо, теперь я увидел эту ошибку: свойства «вызывающий», «вызываемый» и «аргументы» не могут быть доступны для функций строгого режима или объектов аргументов для их вызовов. Что мне тогда использовать? 05.02.2018
  • Я изменил его на имя самой функции, она начинает правильно получать все продукты, но все равно возвращается раньше. 05.02.2018
  • Я думаю, вы можете назвать это как this.getProductsByPage(++page, products) 05.02.2018
  • Сделал это сейчас, как я уже говорил: module.exports.getProductsByPage(++page, products). Я должен использовать module.exports, потому что я его экспортирую. Но, как я уже сказал, он сразу же возвращается пустым. 05.02.2018

Ответы:


1

Работает ли следующее или это дает ошибки/неожиданные результаты?

const getProductsByPage = (page = 1, products = []) => 
  //you need to return the promise here, arrow without {} block
  //  returns the single statement (x=>y = function(x){return y;})
  nuvemshop.get(`products?page=${page}&per_page=200`)
  .then(res => {
    console.log('GET Products PAGE ' + page);
    //you need to return the promise here
    //  call recursively
    return getProductsByPage(
      page+1,
      products.concat(res.data)
    );
  })
  .catch(e => {
    if (e.response.status === 404) {
      console.log('LAST PAGE REACHED')
      return products
    } else
      return e
  });

const sync = (req, res) => {
  // Get all products page by page
  var products = getProductsByPage()
  .then(
    products=>
      res.status(200).send(products)
  ).catch(
    err => 
      res.status(500).send(err)
  );
};


module.exports = {
  sync
}

Ниже приведена версия, которая извлекает 10 страниц одновременно, а не одну за другой. Если что-то пойдет не так, он выдаст результат типа Fail и удалит типы Fail для ответов 404, но любые другие причины сбоя будут сохранены:

const Fail = function(reason){this.reason = reason;};
const isFail = x=>(x&&x.constructor)===Fail;
const isNotFail = x=>!isFail(x);
const getProductsByPage = (pagesInSet=10) => {
  //set up max 3 requests per second
  //const max3 = throttlePeriod(3,1000);
  const recur = (startAt,products) =>
    Promise.all(
      Array.from(new Array(pagesInSet),(_,index)=>index+startAt)
      .map(
        page=>
          //for throttled
          //max3(nuvemshop.get.bind(nuvemshop))(`products?page=${page}&per_page=200`)
          nuvemshop.get(`products?page=${page}&per_page=200`)
          .catch(
            e=>new Fail(e,page)
          )
      )  
    ).then(
      resultSet=>{
        //check if any results came back with 404
        const needStop = resultSet
          .filter(isFail)
          .filter(
            fail=>{
              const [e] = fail;
              return e.response.status === 404;
            }
          );
        if(needStop.length!==0){
          const without404 = products.concat(
            resultSet.filter(
              result=>{
                if(isFail(result)){
                  const [e] = result;
                  return e.response.status !== 404;
                }
                return true;
              }
            )
          );
          return without404;
        }
        //get the next pagesInSet pages
        return recur(startAt+pagesInSet,products.concat(resultSet));
      }
    );
  return recur(1,[]);
}
const sync = (req, res) => {
  // Get all products in sets of 10 parallel requests
  var products = getProductsByPage(10)
  .then(
    products=> {
      //you may want to do something with failed request (non 404)
      //const failed = products.filter(isFail)
      res.status(200).send(products);
    }
  ).catch(
    err => 
      res.status(500).send(err)
  );
};

module.exports = {
  sync
}
06.02.2018
  • По-видимому, это работает, я сделал быстрый тест сейчас. Я просто не мог видеть результаты, потому что мой Postman разбился, в массиве так много элементов, ха-ха. Завтра еще раз протестирую. Некоторые вопросы, почему я должен возвращать его как одно утверждение? Это ярлык для возврата нового обещания? И нельзя ли инкапсулировать все внутри module.exports? 06.02.2018
  • О, и я такой тупой, я пытался сделать его рекурсивным и совершенно забыл оператор возврата, я просто вызывал саму функцию без возврата. 06.02.2018
  • @Deeh Мне нравится называть getProductsByPage вместо arguments.callee, а стрелочные функции не имеют arguments. Единственным утверждением является то, что функции должны возвращать обещание x=>y, которое возвращает y, потому что это то же самое, что и x=>{return y;} или function(x){return y;}. Если вы делаете много запросов, вы можете подумать о параллельном регулировании и перехвате запросов по железной дороге. 06.02.2018
  • @Deeh Добавлен параллельный пример 06.02.2018
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..