“FutureOr”的目的是什么?

Rém*_*let 26 dart

Dart 提供了一个FutureOr类,允许编写:

FutureOr<int> future;

future = 42; // valid
future = Future.value(42); // also valid
Run Code Online (Sandbox Code Playgroud)

如果可以同步读取值,我认为FutureOr将有助于消除由事件循环引起的不必要的延迟。

但事实似乎并非如此,如下所示:

import 'dart:async';

void main() async {
  print('START');
  futureOrExample();
  print('END');
}

void futureOrExample() async {
  FutureOr<int> futureOr = 42;
  print('before await');
  await futureOr;
  print('end await');
}
Run Code Online (Sandbox Code Playgroud)

打印:

START
before await
END
end await
Run Code Online (Sandbox Code Playgroud)

当我期望:

START
before await
end await
END
Run Code Online (Sandbox Code Playgroud)

在这种情况下,为什么FutureOr(或更普遍地await 42)以这种方式工作?

同样,在这种情况下FutureOr的目的是什么,因为它产生与Future相同的结果?

我知道我可以使用SynchronousFuture来达到预期的结果,但我只是想了解FutureOr的用途。

lrn*_*lrn 17

使用的FutureOr,用飞镖2的推出,是为了让你在一个点,现有省道1 API允许为方便起见,同样的事情,只有在可以静态类型的方式提供一个值或未来。

规范的例子是Future.then. 上的签名Future<T>Future<R> then<R>(FutureOr<R> action(T value), {Function onError})

这个想法是你可以对未来的价值采取同步或异步的行动。最初有一个then接受同步回调的chain函数和一个接受异步回调的函数,但使用起来非常烦人,在良好的 Dart 1 风格中,API 被简化为一个then接受函数返回的方法dynamic,然后它检查它是否是未来。

在 Dart 1 中,很容易让你返回一个值或一个未来。Dart 2 没有那么宽松,因此FutureOr引入了该类型以允许现有 API 继续工作。如果我们从头开始编写 API,我们可能会做其他事情,但是将现有的异步代码库迁移到完全不同的东西并不是一种选择,因此该FutureOr类型是作为类型级别的 hack 引入的。

await操作最初也被定义为适用于任何对象,早在FutureOr存在之前。为了一致性和更小的代码,评估为非未来的await ewheree将在未来包装该值并等待它。这意味着对一个值只有一个快速且可重用的检查(它是一个未来,如果没有包装它),然后剩下的代码是一样的。只有一个代码路径。如果await在非Future值上同步工作,则必须有一个同步代码路径通过 运行await,以及一个等待未来的异步路径。这可能会使代码大小增加一倍,例如在编译为 JavaScript 时(或者更糟的是,如果有更多await在同一控制流中s,对于幼稚的实现,您可能会得到指数级的爆发)。即使你避免仅通过调用函数继续同步,它可能会被混淆的一些读者,一await引入异步间隙。周围的错误可能导致竞争条件或以错误的顺序发生的事情。

因此,早于 的原始设计FutureOr是让所有await操作实际上等待。

的引入FutureOr并没有改变这个推理,即使它改变了,现在在人们期望他们的代码实际上为其他微任务运行提供时间的地方等待也将是一个突破性的变化。

  • 是否使用“FutureOr”取决于您设想如何使用 API。仅在 API 中反向使用“FutureOr”(即*接受*“FutureOr”作为参数,或返回“FutureOr”作为参数的函数),不要向 API 用户返回“FutureOr” 。然后他们将不得不浪费时间来弄清楚这是否是未来。你可以选择接受这项工作,但不要把它推给别人。如果您可能都具有接受正常值和未来的函数,则可以将其组合成接受“FutureOr”的函数。否则,可能不会打扰。 (3认同)
  • 这不可能。`FutureOr` *类型*不是一个*类*。`FutureOr&lt;X&gt;` 实际上是一个*联合类型*,代表*一个 `Future&lt;X&gt;` *或*一个 `X` 值。因此,它是这两种类型的超类型,并且它被定义为*至少*这样的超类型(它被定义为任何类型的子类型,该类型也是 `Future&lt;X&gt;` 和 `X` 的超类型`)。不存在与类型相对应的类,就像不存在与函数类型“dynamic”、“void”或“Never”相对应的类一样。他们只是类型。 (2认同)

svo*_*dze 11

对于那些仍然感到困惑的人,我找到了很好的解释https://itnext.io/what-is-futureor-in-dart-flutter-681091162c57,无需深入细节这段代码可以解释目标和实际用例FutureOr

abstract class IDBService {
  FutureOr<String> fetch();
}

class FirebaseRemoteService extends IDBService {
  @override
  Future<String> fetch() async => await 'data';
}

class LocalHiveDbService extends IDBService {
  @override
  String fetch() => 'data';
}
Run Code Online (Sandbox Code Playgroud)

所以在实现中IDBService

现在返回类型可以同时是Future或String!


Rém*_*let 6

await关键字总是锁定功能执行。

写作:

await 42
Run Code Online (Sandbox Code Playgroud)

相当于:

await Future.value(42)
Run Code Online (Sandbox Code Playgroud)

原因是:

  • 这是await在 Javascript 中的工作方式
  • 它使行为await一致。

那么,这样做的目的是FutureOr什么?

FutureOr从来没有打算作为一种潜在的await同步方式。

相反,它是Future.

没有FutureOr,编写以下内容将无法编译:

Future(() {
  return 42; // compile error, not a Future
});

Future<int> future;
future.then((value) {
  return value * 2; // compile error, not a Future
});

Run Code Online (Sandbox Code Playgroud)

相反,我们必须Future.value像这样将所有值包装起来:

Future<int> future;
future.then((value) {
  return Future.value(value * 2);
});
Run Code Online (Sandbox Code Playgroud)