Javascript 如何从Node.js流中释放数据
我使用Java脚本API已经有一段时间了,但这是我第一次尝试从一个永远不会发出Javascript 如何从Node.js流中释放数据,javascript,node.js,stream,Javascript,Node.js,Stream,我使用Java脚本API已经有一段时间了,但这是我第一次尝试从一个永远不会发出'done'的活动流中采样。我的目标是每小时从流中获取一定数量的样本。该流连接并流式传输了大量信息,但我无法将返回的数据转换为可以对其进行进一步处理的格式(就像我熟悉的数据科学工作流) 感觉我已经盯着文档看了好几天了,注意到最简单的例子是将可读的流传输到服务器上的文件中。对于我的应用程序来说,这似乎效率低下。(必须将其写入一个文件,只需再次读入以对其进行更多处理,然后再通过fetch 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:
- The data must be fetched as a streamed HTTP response body
- The response stream must be parsed by a JSON parser as data is streamed from the response
- 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数据的结构对于确定必须如何解析数据流非常重要。