【问题标题】:Extending a Future and/or preserving await functionality扩展 Future 和/或保留等待功能
【发布时间】:2022-01-10 01:35:13
【问题描述】:

我想扩展 Future 类并为其提供更多功能,同时保留 await 关键字的功能。据我了解,Futures 不能直接在 Dart 中扩展,但也许还有另一种方法可以实现我想要的?

我试图创建的类实际上是一种与 API 交互的机制。服务器类似于 RPC,因为它的 API 在请求打开时可以是双向的(消息可以在服务器和客户端之间来回传递,直到请求被认为已解决)。

为了使客户端库更可用,我正在尝试创建一个 Request 类,它具有普通 Future 的所有优点,但也能够使用有效侦听更新的 when()on() 函数在未来的决议中。

一些sudo的使用代码:

Request(args)
  .when('SomeEvent', (event) => print('An update: $event'))
  .then((response) => print('The final response: $response'))
  .onError((err) => print('Some error: $err'));

// This also needs to work:

final response = await Request(args);

到目前为止,我有这样的东西,但 await 关键字不起作用:

class Request {
  final Completer _completer = Completer();

  Request(args) {
    /* Setup and make some request to an API and respond/update using response|error|update */
  }

  Future<dynamic> then(fn) async {
    // Should this actually return a Request?
    return _completer.future.then(fn);
  }

  Future<dynamic> onError(fn) async {
    // Should this actually return a Request?
    return _completer.future.onError(fn);
  }

  Request when(String eventName, Function fn) {
    /* attach a listener/stream which fires fn on update */
    return this;
  }

  void _response(res) {
    _completer.complete(res);
  }

  void _error(err) {
    _completer.completeError(err);
  }

  void _update(upd) {
    /* Some update from the request is given */
  }
}

我在 Dart 中尝试的东西是不可能的吗?

【问题讨论】:

  • 您可以打开 dart-sdk/lib/async/future_impl.dart 并检查 Future 的实现。但是这样做的主要目的是什么?如果我正确理解了您,您希望创建部分行为类似于 Stream 的 Future,但 Stream 和 Future 具有不同的生命周期。 Future 返回一个结果,但 Stream 可能会在您收听时产生一个或多个结果。
  • 我可能应该提到我正在创建一个面向客户端的库并试图抽象出流的一些复杂性。用户可能对“更新”感兴趣,也可能不感兴趣,所以让它表现得更像未来对我来说是有意义的。
  • @shennan 我真的不明白这个“超级”未来应该如何运作,因为你在谈论只有一个价值的未来。但是你想让它模拟多个值的可能性。但是代码应该如何表现以使其表现得像一个正常的未来?这听起来更像是您想创建一个包含Stream 内部的类,并具有一个返回Future 的方法,该方法在关闭时以Stream 的最后一个值完成?
  • 正确。我想利用“等待”的可用性,同时允许流的灵活性。这是一个面向客户的库,客户与它交互的方式会有所不同。 SuperFuture 仍将仅解析为一个值,但将在实例化和完成之间提供更新。显然,这些事情可以通过附加到类的单独方法来完成,但我的圣诞节列表的顶部是按照我在我的 OP 中描述的方式将功能链组合在一起。我的预感是我会因为无法完成而被推回。这是一个公平的评估吗?
  • 我已经更新了答案以解释更多关于用例的信息。我可能通过称这个类为“SuperFuture”而混淆了这种情况。实际上,该类是一个 Request 类,它充当既是 Future 又是流。

标签: dart async-await future


【解决方案1】:

我建议不要扩展 Future 接口,而是让您的 Request拥有未来而不是成为未来。

然后你可以做await request.resultrequest.when(...),而不必重新实现整个Future API。

如果您坚持让Request 成为Future,您只需将implements Future&lt;Object?&gt; 添加到类...然后实际实现整个Future API。不需要做onError(这是一种适用于任何Future的扩展方法,包括你的Request),但你需要实现thencatchErrorwhenCompleteasStream和@987654338 @ 正确且完全(支持所有参数并具有正确的类型)。 然后你就可以用await来使用你的类了。

如果你这样做,你可以让这些函数也返回Request,如果你让Request泛型(class Request&lt;T&gt; implements Future&lt;T&gt;),因为.then&lt;int&gt;(...)需要返回一个Future&lt;int&gt; .然后,您需要一个将when/on 事件转发到新期货的策略。

这样做要容易得多,只需将内部未来与进度回调分开即可。

另见CancelableOperation

【讨论】:

    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 2011-06-04
    • 2015-07-06
    • 1970-01-01
    相关资源
    最近更新 更多