【问题标题】:Cannot build up a string using StringBuffer and a server response无法使用 StringBuffer 和服务器响应构建字符串
【发布时间】:2020-02-24 10:17:20
【问题描述】:

我正在尝试通过 Dart 从 this link 获取数据。由于我正在使用基于dart:io 库的HttpClientResponse 实例来listen 从上述链接获得的数据,因此我认为StringBuffer 的实例将是最好的选择捕获接收到的数据。这将帮助我以增量方式构建响应字符串。但似乎我没有正确使用StringBuffer,因为最后响应字符串(存储在receivedBuffer)仍然是空的。

代码:

import 'dart:io';
import 'dart:convert';

void main() async
{
  StringBuffer receivedBuffer = new StringBuffer("");
  String url = "https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty";

  HttpClient client = new HttpClient();
  HttpClientRequest request = await client.getUrl(Uri.parse(url));
  HttpClientResponse response = await request.close();

  print("[info] Fetch successful. Proceeding to transform received data ...");
  response.transform(utf8.decoder).listen((contents) => receivedBuffer.write(contents));

  print("[info] Done. Contents:\n");
  print(receivedBuffer);
}

输出:

[info] Fetch successful. Proceeding to transform received data ...
[info] Done. Contents:


另外,如果我写print(contents),而不是receivedBuffer.write(contents),那么所有 所需数据按预期打印。但是在尝试将contents 写入recievedBuffer 时,似乎receivedBuffer 甚至没有更新一次。 我阅读了this article,并试图将那里的答案合并到我的代码中。准确地说,我使用了Completer 实例来解决我的问题,但这并没有帮助。

上面提供的代码有什么问题?

【问题讨论】:

  • 尝试在onDone函数中打印缓冲区,您可以在listen()函数中设置该缓冲区

标签: dart


【解决方案1】:

您没有等待流完成。

在listen 调用中,您为流事件设置了接收器,但您无需等待事件到达。 您可以在listen 调用中添加onDone 参数并在那里执行某些操作,但更有可能您只想在这里等待它,然后我建议:

  await response.transform(utf8.decoder).forEach(receivedBuffer.write);

使用forEach 通常是您在调用listen 时想要的,但不记得返回的订阅。或者使用await for:

  await for (var content in response.transform(utf8.decoder)) {
    receivedBuffer.write(content);
  }

(在大多数情况下对应于forEach 调用)。

【讨论】:

  • 还有2个问题:(1)如果我直接使用await response.transform(utf8.decoder).listen((content) => receivedBuffer.write(content)),会不会导致其他问题?因为我使用了这个语句,这个语句的效果和你建议的语句一样。 (2) Dart 是否更喜欢在流完成之前执行流侦听类型语句之外的语句?我相信这是真的,因为它可以帮助我解释我的代码在合并@Mattia 建议的更改后生成的结果。
  • 1) 您不能等待调用listen 的结果。它返回一个流订阅,而不是未来。等待它只会插入一个微小的延迟,它不会等待流完成。 forEach 调用确实会返回一个在流完成时完成的未来。所以是的,同样的问题。
  • 2) 当你调用listen时,它会立即返回一个流订阅,然后开始等待流上的异步事件。 call 之后的代码将立即继续运行。然后稍后,可能更晚,事件将出现在流上并调用您附加到订阅的事件处理程序。当流结束时,如果结束,则调用 onDone 处理程序。这些回调中发生的事情完全取决于您,因此如果您需要其他代码来等待流结束,您需要在您的 onDone 处理程序中告诉他们。
  • 关于上面的评论,让我们假设一个 listen 语句已经被放置在某个已经执行的函数foo() 中(所有这意味着除了listen one) 并且当前正在执行一些其他函数bar()。当bar() 被执行时,上面提到的listen 语句接收到它的最后一个值,然后Dart 会直接跳回到那个listen 语句的onDone 参数还是等待bar()的执行结束?
  • 假设流被调用StreamController.close的人关闭。这会安排一个微任务来调用onDone 处理程序。然后在控制返回到微任务队列之前不会发生任何进一步的事情。这意味着bar 必须返回,调用bar 的代码也必须返回,直到微任务队列最后调用的函数返回。然后微任务可以继续下一个计划任务(或者如果没有,事件循环可以继续下一个事件)。在某些时候,计划的微任务将运行以调用onDone 处理程序。
猜你喜欢
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多