Javascript 如何从Node.js流中释放数据

Javascript 如何从Node.js流中释放数据,javascript,node.js,stream,Javascript,Node.js,Stream,我使用Java脚本API已经有一段时间了,但这是我第一次尝试从一个永远不会发出'done'的活动流中采样。我的目标是每小时从流中获取一定数量的样本。该流连接并流式传输了大量信息,但我无法将返回的数据转换为可以对其进行进一步处理的格式(就像我熟悉的数据科学工作流) 感觉我已经盯着文档看了好几天了,注意到最简单的例子是将可读的流传输到服务器上的文件中。对于我的应用程序来说,这似乎效率低下。(必须将其写入一个文件,只需再次读入以对其进行更多处理,然后再通过fetch API将其发送到浏览器进行渲染,或

我使用Java脚本API已经有一段时间了,但这是我第一次尝试从一个永远不会发出
'done'
的活动流中采样。我的目标是每小时从流中获取一定数量的样本。该流连接并流式传输了大量信息,但我无法将返回的数据转换为可以对其进行进一步处理的格式(就像我熟悉的数据科学工作流)

感觉我已经盯着文档看了好几天了,注意到最简单的例子是将可读的流传输到服务器上的文件中。对于我的应用程序来说,这似乎效率低下。(必须将其写入一个文件,只需再次读入以对其进行更多处理,然后再通过fetch API将其发送到浏览器进行渲染,或将其发送到项目的mongoDB进行长期存储和深入分析。我非常确定有一种方法可以将JSON设置为
const
var
,我只是不知道米利尔对它很满意

如何将数据放入
保存的
Java脚本变量中?我需要对代码进行哪些更改或添加才能继续操作和处理返回的JSON

const needle = require('needle');

const token = process.env.BEARER_TOKEN;
const streamURL = 'https://api.twitter.com/2/tweets/sample/stream';

function streamConnect() {
    const options = {
        timeout: 2000,
    };

    const stream = needle.get(
        streamURL,
        {
            headers: {
                Authorization: `Bearer ${token}`,
            },
        },
        options
    );

    stream
        .on('data', (data) => {
            try {
                const json = JSON.parse(data);
                // console.log(json);
            } catch (e) {
                // Keep alive signal received. Do nothing.
            }
        })
        .on('error', (error) => {
            if (error.code === 'ETIMEDOUT') {
                stream.emit('timeout');
            }
        });

    return stream;
}

function getTweetSample() {
    const s = streamConnect();
    const chunks = [];
    s.on('readable', () => {
        let chunk;
        while (null !== (chunk = s.read())) {
            chunks.push(chunk);
        }
    });
    setInterval(() => {
        s.destroy();
    }, 3000);
    return chunks;
}

const saved = API.getTweetSample();
console.log('saved: ', saved);

// Above returns
// "saved: []"

// Expecting 
// "saved:
{
{
  data: {
    id: '1301578967443337***',
    text: 'See bones too so sure your weight perfect!'
  }
}
{
  data: {
    id: '1301578980001230***
    text: 'Vcs perderam a Dona Maria, ela percebeu q precisa trabalhar e crescer na vida, percebeu q paga 40% de imposto no consumo enquanto políticos q dizem lutar por ela, estão usufruindo dos direitos q ela nunca vai ter Three steps to tackle the challenge:

  1. The data must be fetched as a streamed HTTP response body
  2. The response stream must be parsed by a JSON parser as data is streamed from the response
  3. The stream shall terminate after 20 elements have been parsed by the JSON parser
The example code from the OP already illustrates how to solve (1).

There's a selection of libraries out there to parse a stream of JSON data on-the-fly to solve (2). My personal preference is
stream-json
since it only requires a single line of code in our pipeline.

Finally, (3) will require the code to terminate the incoming stream before it completes. This will cause nodejs to throw a
ERR_STREAM_PREMATURE_CLOSE
error, which can be handled by a targeted catch statement.

Combining these steps will become something like the following executable POC. I don't have a Twitter API token, but I think this will work:

const stream = require('stream');
const util = require('util');
const got = require('got');
const StreamValues = require("stream-json/streamers/StreamValues.js");

(async () => {
  const token = "<YOUR API TOKEN>";

  const dataStream = got.stream('https://api.twitter.com/2/tweets/sample/stream', {
    headers: { "Authorization": `Bearer ${token}` },
  });

  // This array will by filled by JSON parsed objects from the HTTP response
  const dataPoints = [];
    
  await util.promisify(stream.pipeline)(
    // This readable stream [dataStream] will emit the incoming HTTP body as string data
    dataStream,
    // The string data is then JSON parsed on the fly by [stream-json]
    StreamValues.withParser(),
    // Finally, we iterate over the the JSON objects and push them to the [dataPoints] array.
    async function(source){
      for await (const parsedObject of source){
        dataPoints.push( parsedObject.value );

        if( dataPoints.length === 20 ){
          // When we reach 20 data points, the stream is forcefully terminated
          dataStream.destroy();
          return;
        }
      }
    }
  )
    // Prematurely terminating the stream will cause nodejs to emit a [ERR_STREAM_PREMATURE_CLOSE] 
    // error. If it is OK to return more than 20 elements, you could try to remove the 
    // [return] statement on L28;
    .catch(error => (error.code !== "ERR_STREAM_PREMATURE_CLOSE" && Promise.reject(error)));
}())
  .catch(console.error);
const needle=require('needle');
const token=process.env.BEARER\u token;
常量streamURL=https://api.twitter.com/2/tweets/sample/stream';
函数streamConnect(){
常量选项={
超时时间:2000,
};
const stream=needle.get(
streamURL,
{
标题:{
授权:`Bearer${token}`,
},
},
选择权
);
流动
.on('数据',(数据)=>{
试一试{
const json=json.parse(数据);
//log(json);
}捕获(e){
//收到“保持活动”信号。请不要执行任何操作。
}
})
.on('错误',(错误)=>{
如果(error.code==='ETIMEDOUT'){
emit('timeout');
}
});
回流;
}
函数getTweetSample(){
常数s=streamConnect();
常量块=[];
s、 在('可读',()=>{
让块;
while(null!==(chunk=s.read()){
推(chunk);
}
});
设置间隔(()=>{
s、 破坏();
}, 3000);
返回块;
}
const saved=API.getweetSample();
console.log('saved:',saved);
//以上回报
//“已保存:[]”
//期待
//“保存:
{
{
数据:{
id:'130157896743337***',
文字:“也看看骨头,确保你的体重完美!”
}
}
{
数据:{
id:'130157890001230***

正文:“风险投资家对多纳·玛丽亚、埃拉·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·佩尔西·多纳·多纳

  • 数据必须作为流式HTTP响应主体获取
  • 响应流必须由JSON解析器解析,因为数据是从响应流传输的
  • JSON解析器解析20个元素后,流将终止
  • OP中的示例代码已经说明了如何求解(1)

    有很多库可以在运行中解析JSON数据流以解决问题(2)。我个人的偏好是
    streamJSON
    ,因为它只需要管道中的一行代码

    最后,(3)将要求代码在传入流完成之前终止它。这将导致nodejs抛出
    ERR\u stream\u PREMATURE\u CLOSE
    错误,这可以由目标catch语句处理

    结合这些步骤将成为类似以下可执行POC的东西。我没有Twitter API令牌,但我认为这会起作用:

    const stream=require('stream');
    const util=require('util');
    const-got=require('got');
    const StreamValues=require(“stream json/streamers/StreamValues.js”);
    (异步()=>{
    const token=“”;
    const dataStream=get.stream('https://api.twitter.com/2/tweets/sample/stream', {
    标头:{“授权”:`承载${token}`,
    });
    //此数组将由HTTP响应中的JSON解析对象填充
    常量数据点=[];
    wait util.promisify(stream.pipeline)(
    //此可读流[dataStream]将以字符串数据的形式发出传入HTTP正文
    数据流,
    //然后通过[stream JSON]动态解析字符串数据
    StreamValues.withParser(),
    //最后,我们迭代JSON对象并将它们推送到[dataPoints]数组。
    异步函数(源){
    用于等待(源的const parsedObject){
    dataPoints.push(parsedObject.value);
    如果(dataPoints.length==20){
    //当我们到达20个数据点时,流被强制终止
    destroy();
    返回;
    }
    }
    }
    )
    //过早终止流将导致NodeJ发出[错误\u流\u过早\u关闭]
    //错误。如果可以返回20个以上的元素,可以尝试删除
    //[返回]L28上的声明;
    .catch(error=>(error.code!==“ERR\u STREAM\u PREMATURE\u CLOSE”&&Promise.reject(error));
    }())
    .catch(控制台错误);
    
    这是否正确地概括了您的问题:1)连接到远程JSON API。2)从API下载/流数据,并对响应进行流解析3)在收到20个样本后优雅地终止流?是的,我认为这是准确的,还有第四步,即将数据返回到const或var进行进一步处理。您能否提供API?JSON数据的结构对于确定必须如何解析数据流非常重要。