我怎样才能"睡"Dart程序

Vin*_*nie 67 unit-testing mocking dart

我喜欢在我的Dart应用程序中模拟异步Web服务调用以进行测试.为了模拟这些模拟调用响应的随机性(可能是乱序),我想编程我的模拟等待(睡眠)一段时间后再返回'Future'.

我怎样才能做到这一点?

Tim*_*mmm 148

2019版:

在异步代码中

await Future.delayed(Duration(seconds: 1));
Run Code Online (Sandbox Code Playgroud)

同步代码

import 'dart:io';

sleep(Duration(seconds:1));
Run Code Online (Sandbox Code Playgroud)

注意:这会阻塞整个进程(隔离),因此不会处理其他异步函数。它也无法在网络上使用,因为 Javascript 实际上是仅异步的。

  • `sleep()` 完全阻塞了整个隔离。Dart 代码在休眠时根本不会运行。它可能会编译成类似于 C++ 的 `std::this_thread::sleep_for` 的东西。`Future.delayed()` 安排异步函数稍后恢复,但随后它将控制权返回给 Dart 事件循环,以便其他异步函数可以继续运行。 (7认同)

Sha*_*uli 76

您还可以使用Future.delayed工厂在延迟后完成未来.以下是两个在延迟后异步返回字符串的函数的示例:

import 'dart:async';

Future sleep1() {
  return new Future.delayed(const Duration(seconds: 1), () => "1");
}

Future sleep2() {
  return new Future.delayed(const Duration(seconds: 2), () => "2");
}
Run Code Online (Sandbox Code Playgroud)

  • 我想没用,它只是一个占位符来做你的计算 (3认同)
  • `()=>“ 1”`的目的是什么? (2认同)

Set*_*add 42

它并不总是你想要的(有时你想要的Future.delayed),但是如果你真的想睡在你的Dart命令行应用程序中,你可以使用dart:io sleep():

import 'dart:io';

main() {
  sleep(const Duration(seconds:1));
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您正在构建Web应用程序,则'dart:io'库不可用 (9认同)
  • 来自文档:请谨慎使用,因为*在[sleep]调用中被阻塞时,*不能单独处理*异步操作。 (3认同)
  • **警告**:这是同步的!它会停止主线程!(我真是个傻瓜,我做了 `await sleep()` 并期望其他作业在睡眠期间运行:( (2认同)

Spk*_*ngR 16

我发现Dart中有几种实现可以使代码延迟执行:

new Future.delayed(const Duration(seconds: 1)); //recommend

new Timer(const Duration(seconds: 1), ()=>print("1 second later."));

sleep(const Duration(seconds: 1)); //import 'dart:io';

new Stream.periodic(const Duration(seconds: 1), (_) => print("1 second later.")).first.then((_)=>print("Also 1 second later."));
//new Stream.periodic(const Duration(seconds: 1)).first.then((_)=>print("Also 1 second later."));
Run Code Online (Sandbox Code Playgroud)


小智 14

对于Dart 2+语法,在异步函数上下文中:

import 'package:meta/meta.dart'; //for @required annotation

void main() async {
  void justWait({@required int numberOfSeconds}) async {
    await Future.delayed(Duration(seconds: numberOfSeconds));
  }

  await justWait(numberOfSeconds: 5);
} 
Run Code Online (Sandbox Code Playgroud)


Mar*_* Ge 11

由于最佳答案的编辑队列已满,这里是该问题的最新工作改编:

在异步代码中:

await Future<void>.delayed(const Duration(seconds: 1));
Run Code Online (Sandbox Code Playgroud)

在同步代码中:

import 'dart:io';
sleep(const Duration(minutes: 1));
Run Code Online (Sandbox Code Playgroud)

注意:这会阻塞整个进程(隔离),因此其他异步函数将不会被处理。它在网络上也不可用,因为 Javascript 实际上是异步的。


rao*_*son 8

Dart 在单个进程或线程(即事件循环)中运行所有代码。因此async,实际上,块/方法中的代码也在某种类型和顺序的“全局”序列中运行,以馈送事件循环。换句话说:Dart 中没有,只有一个“线程”(暂时不包括 Isolates,见下文)。

当必须模仿随着时间的推移到达的数据sleep(例如通过流)时,可能会遇到在块/方法中运行的代码中使用的陷阱async。思考:“我的代码触发一个新线程并愉快地继续前进,并在 UI 层和所有内容上保持响应! ”。但事实并非如此:在 Dart 中,你只是射中了自己的膝盖

当在任何地方使用时sleep,而不仅仅是在异步代码中,这将停止“唯一”事件循环,并且每个“线程”都被阻塞,即所有代码,所有内容......(......因为实际上没有“线程” “就像 Java 中的例子)。

注意:最重要的是,UI 将阻塞,不会重新绘制,并且不会响应任何输入。期间发生的所有幕后事件sleep,只有在“醒来”之后才会变得可见。

举个例子,考虑一个将项目附加到自身的列表(可能通过流/StreamBuilder)。在“真实的应用程序生活”中,数据通常来自“外部源”,它以延迟的、不可预测的方式发送数据。所以,一切都好……

...但是,当从代码中模仿数据时,例如通过按钮事件,涉及sleep同步或异步,并不重要,列表只会在最后所有睡眠结束时重新绘制。此外,任何其他按钮事件(例如)在此之后也不会由事件循环调度。

考虑这段代码:

Future<VoidCallback?> asyncWithSleep() async {
  print('start');
  for (var i = 0; i < 5; i++) {
    sleep(const Duration(seconds: 1));
    print(i);
  }
  print('end');
  return null;
}
Run Code Online (Sandbox Code Playgroud)

印刷:

flutter: start
flutter: 0
flutter: 1
flutter: 2
flutter: end
Run Code Online (Sandbox Code Playgroud)

如果您期望 end 会在数字之前打印,那么现在大声说出来:sleep在 Dart 中导致所有线程等待”。基本上,除非您从上到下运行命令行脚本,或者在隔离中运行代码,否则请忘记sleep.

例如,为了模拟来自 Web 服务、数据库或底层平台等来源的数据,您可以Future.delayed为您想要模拟的每条数据生成一个 。

void syncWithDelayedFutureAndNoSyncDownTheLine() { // doesn't have to be async but could, if Future setup takes too long
  print('start');
  for (var i = 0; i < 3; i++) {
    Future.delayed(const Duration(seconds: i + 1), () {
      print(i);
    });
  }
  print('end');
  return null;
}
Run Code Online (Sandbox Code Playgroud)

这不会阻塞 UI 或其他任何东西。它设置了三个将来异步运行的代码块,分别在 1、2 和 3 秒内到达 for 循环。

印刷:

flutter: start
flutter: end
flutter: 0
flutter: 1
flutter: 2
Run Code Online (Sandbox Code Playgroud)

(如果每秒模拟的数据看起来太无聊,请在参数的 Duration 参数中添加一些摆动和随机性Future.delayed......)

创建用于模拟或测试的未来事件的关键正确设置未来的持续时间。异步代码中的阻塞无法按预期工作,因为它会阻塞所有代码。

如果您仍然认为需要sleep在程序中的任何地方使用,请查看Dart 的Isolates. 我还没有使用过它们,但从我所看到的来看,它们对我来说有点像 Java 线程,没有共享内存的负担,而且有很多陷阱。然而,它们的目的是作为“后台工作人员”,用于计算/时间密集型处理,当从相同的主隔离main()运行时,这可能会使程序的其余部分变得缓慢。


Jan*_*sen 5

这是一个有用的模拟,可以使用可选参数来模拟错误:

  Future _mockService([dynamic error]) {
    return new Future.delayed(const Duration(seconds: 2), () {
      if (error != null) {
        throw error;
      }
    });
  }
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

  await _mockService(new Exception('network error'));
Run Code Online (Sandbox Code Playgroud)