Поддерживает ли библиотека Node.js «request» поток асинхронных ответов? - PullRequest
0 голосов
/ 09 апреля 2019

Я несколько новичок в библиотеках Node.js и пытаюсь понять, как использовать асинхронную итерацию для потока ответов HTTP.Моя общая цель - прочитать большой поток ответов и обработать его по мере поступления кусков, в настоящее время через функцию генератора.Я не могу сохранить весь ответ в памяти для обработки.

Я использую библиотеку request для выполнения HTTP-запроса следующим образом.

const request = require("request");

// contrived chunk-by-chunk stream processing 
async function* getChunks(stream) {
  for await (const chunk of stream) {
    yield chunk[0];
  }
}

async function doWork() {
  var response = request.get("https://pastebin.com/raw/x4Nn0Tby");
  for await (c of getChunks(response)) {
    console.log(c);
  }
}

Когда я запускаю doWork(),Я получаю сообщение об ошибке, в котором говорится, что переменная stream для getChunks() не асинхронно-итерируемая.

TypeError: поток не асинхронно-итерируемый

Это удивительно,как я думал, что все readable-потоки, как правило, асинхронно-итерируемы, и что библиотека запросов возвращает поток, когда обратный вызов не предоставляется.Когда я заменяю request.get(...) на fs.createReadStream(...) на какой-то локальный файл, все работает как положено.

Возможно, библиотека request не поддерживает это.Если да, что мне нужно сделать для обработки потоков ответов HTTP с помощью асинхронной итерации?

Использование Node.js 11.13 и request 2.88.0.

Ответы [ 3 ]

1 голос
/ 10 апреля 2019

Я провел еще несколько экспериментов с библиотеками request и request-promise-native и не думаю, что это возможно при текущей реализации.Результирующий поток вообще не выглядит асинхронно-итерируемым.Кроме того, правильная реализация должна будет await, чтобы ответ возвращался перед обработкой потока (как предложено @ JBone's answer ).Но если вы звоните await request.get(...), вы извлекаете все содержимое ответа, что нежелательно для больших ответов.

const r = require("request");
const rpn = require("request-promise-native");

// contrived chunk-by-chunk stream processing 
async function* getChunks(stream) {
  for await (const chunk of stream) {
    yield chunk[0];
  }
}

async function doWork() {
  const url = "https://pastebin.com/raw/x4Nn0Tby";
  const response = r.get(url);         // returns a non-async-iterable object.
  const response2 = await rp.get(url); // returns the contents of url

  for await (c of getChunks(response)) {  // yields response not async-iterable error.
    console.log(c);
  }
}

Мое решение этой проблемы заключалось в замене использования request и request-promise-nativeс библиотекой axios.Библиотеки функционально похожи, но axios позволяет указать, что запрос должен разрешаться в поток;как и ожидалось, поток является асинхронным.

const axios = require("axios");

async function doWork() {
  var response = await axios.request({
    method: "GET",
    url: "https://pastebin.com/raw/x4Nn0Tby",
    responseType: "stream",
  });

  for await (c of getChunks(response)) {  // async-iteration over response works as expected.
    console.log(c);
  }
}
1 голос
/ 10 апреля 2019

Простой ответ: нет, это не так.Возможно, вы захотите использовать оболочку, основанную на обещаниях, около request, например request-обещание , которая также работает с async / await.

Подробности: Обратите вниманиечто request было устарело его создателем , и, следовательно, будет прекращено.Это означает, что рано или поздно вам, скорее всего, придется переключиться на другое решение, такое как axios , superagent или needle , чтобы назвать несколько.

Конечно, вы должны оценить эти модули и выяснить, что лучше всего соответствует вашим потребностям, но моя личная рекомендация - начать с axios, так как в прошлом у меня был очень хороший опыт,однако, YMMV.

0 голосов
/ 09 апреля 2019

Похоже, вам придется использовать другие альтернативы, как они упоминались в документации к модулю request, которую вы можете найти здесь. https://www.npmjs.com/package/request

request supports both streaming and callback interfaces natively. If you'd like 
request to return a Promise instead, you can use an alternative interface wrapper for 
request. These wrappers can be useful if you prefer to work with Promises, or if 
you'd like to use async/await in ES2017.

Several alternative interfaces are provided by the request team, including:

request-promise (uses Bluebird Promises)
request-promise-native (uses native Promises)
request-promise-any (uses any-promise Promises)`

мой ответ на следующий вопрос:

Я думаю, вы можете создать async await пользовательский метод, который это делает.

async function doMyWork() {
try {
 const response = await myOwnRequest(url); 
 } catch (e) {
   console.log ('the error', e);
 }  
}

function myOwnRequest(url) {
  return new Promise(function (resolve, reject) {
   const resp = request.get(url);
   if(resp) {
    resolve();
   } else {
     reject();
   }
});
}
...