我喜欢在我的Dart应用程序中模拟一个异步web服务调用进行测试。为了模拟这些模拟调用响应的随机性(可能是无序的),我想编程我的模拟在返回“Future”之前等待(睡眠)一段时间。
我该怎么做呢?
我喜欢在我的Dart应用程序中模拟一个异步web服务调用进行测试。为了模拟这些模拟调用响应的随机性(可能是无序的),我想编程我的模拟在返回“Future”之前等待(睡眠)一段时间。
我该怎么做呢?
当前回答
它并不总是你想要的(有时你想要Future.delayed),但如果你真的想在Dart命令行应用程序中睡觉,你可以使用Dart:io的sleep():
import 'dart:io';
main() {
sleep(const Duration(seconds:1));
}
其他回答
由于顶部答案的编辑que是完整的,这里是该问题的最新工作改编:
在异步代码中:
await Future<void>.delayed(const Duration(seconds: 1));
同步代码:
import 'dart:io';
sleep(const Duration(minutes: 1));
注意:这将阻塞整个进程(隔离),因此其他异步函数将不会被处理。它也不能在网络上使用,因为Javascript是纯异步的。
我发现在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."));
这是一个有用的模拟,可以接受一个可选参数来模拟错误:
Future _mockService([dynamic error]) {
return new Future.delayed(const Duration(seconds: 2), () {
if (error != null) {
throw error;
}
});
}
你可以这样使用它:
await _mockService(new Exception('network error'));
Dart在单个进程或线程(事件循环)中运行您的所有代码。因此,异步块/方法中的代码,实际上是在某种“全局”序列中运行的,这种“全局”序列提供了事件循环。 换句话说:在Dart中没有,只有一个“线程”(目前不包括“隔离”,见下文)。
当必须模拟数据时,随着时间的推移到达,例如通过流,人们可能会陷入在异步块/方法中运行的代码中使用睡眠的陷阱。思考:“我的代码启动了一个新的线程,并愉快地继续前进,并在UI层保持响应!” 但事实并非如此:在《Dart》中,你只是射中了自己的膝盖。
当在任何地方使用sleep时,不仅仅是在异步代码中,这将停止“唯一的”事件循环,每个“线程”都被阻塞,也就是说,所有的代码,所有的东西……(…因为实际上不像在Java中那样有“线程”)。
注意:最重要的是,UI会阻塞,不会重绘,也不会响应任何输入。所有在睡眠期间发生的幕后事件,只有在“醒来”后才会变得可见。
例如,假设一个列表将项目附加到自身(可能通过流/ StreamBuilder)。在“真实的应用生活”中,数据通常来自“外部来源”,以延迟的、不可预测的方式发送数据。所以,一切都好……
...但是当数据在你的代码中被模仿时,比如通过一个按钮事件,涉及睡眠,sync或async,没有关系,列表只会在最后重新绘制,当所有的睡眠结束时。此外,任何其他按钮事件,例如,也不会分派事件循环,直到之后。
考虑下面的代码:
不
Future<VoidCallback?> asyncWithSleep() async {
print('start');
for (var i = 0; i < 5; i++) {
sleep(const Duration(seconds: 1));
print(i);
}
print('end');
return null;
}
打印:
flutter: start
flutter: 0
flutter: 1
flutter: 2
flutter: end
如果您希望end在数字之前打印,那么现在大声说出来:“sleep in Dart导致所有线程等待”。基本上,除非您从上到下运行命令行脚本,或者在隔离中运行代码,否则请忘记睡眠。
例如,要模拟来自某些源的数据,如web服务、数据库或底层平台,你可以为你想要模拟的每一块数据生成Future.delayed。
DO
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;
}
这既不会阻塞UI也不会阻塞其他任何东西。它设置了三块将来异步运行的代码,分别在for循环的1秒、2秒和3秒内。
打印:
flutter: start
flutter: end
flutter: 0
flutter: 1
flutter: 2
(如果每秒钟模拟一次数据似乎太无聊,可以在Future.delayedparameter的Duration参数中添加一些波动和随机性…)
为模拟或测试创建未来事件的关键是正确设置未来的持续时间。在异步代码中阻塞并不像预期的那样工作,因为它阻塞了所有。
如果您仍然认为需要在程序的任何地方使用睡眠,请查看Dart的隔离。我还没有使用过它们,但据我所知,它们看起来有点像Java线程,没有共享内存的负担,而且有很多陷阱。然而,它们是作为“后台工作人员”,用于计算/时间密集的处理,当从相同的main()运行时,这可能会使程序的其余部分变得缓慢,也就是说,在相同的main隔离中。
它并不总是你想要的(有时你想要Future.delayed),但如果你真的想在Dart命令行应用程序中睡觉,你可以使用Dart:io的sleep():
import 'dart:io';
main() {
sleep(const Duration(seconds:1));
}