我正在尝试Dart,我无法解释两个观察结果。
onDone
”处理程序不会启动。onPause
”和“ onResume
”处理程序仅触发一次。代码:
import 'dart:async';
import 'dart:io';
/// This class encapsulates all the necessary data used by the "onValue" event
/// handler (the construct avoids using global variables).
class OnValueHandlerContainer {
static StreamSubscription<int> _streamSubscriber;
static setStreamSubscriber(StreamSubscription<int> stream) {
_streamSubscriber = stream;
}
// This static method is the handler executed when a event is received through
// the stream.
//
// WARNING: you have absolutely no idea when this handler will be executed.
// Do not assume that it will be executed right after the execution of the code
// that emits an event. It may be executed several lines (of codes) below the
// line that emits the event. It may well be executed after the end of the
// script.
static void onValue(int value) {
// At this point: the state of the subscription is (inevitably) "active".
print("onValue: An event has been raised. The associated value is ${value}!");
print(" Pause the subscription. Wait for 1 second. Resume the subscription");
// Note 1: once a Dart function starts executing, it continues executing until
// it exits. When managing interrupts in C, it is necessary to protect
// interrupt handlers from being interrupted. This is not the case in
// Dart : a function (and, thus, an event handler) cannot be interrupted
// by the occurrence of another event.
// => The code below has no sense, other than experimentation.
// Note 2: while paused, the subscription will not fire any events. If it receives
// events from its source, they will be buffered until the subscription
// is resumed.
_streamSubscriber.pause();
sleep(Duration(seconds: 1));
_streamSubscriber.resume();
// At this point: the state of the subscription is "active".
}
}
main() async {
// Create a controller.
// A StreamController gives you a new stream and a way to add events to the stream
// at any point, and from anywhere. The stream has all the logic necessary to handle
// listeners and pausing. You return the stream and keep the controller to yourself.
StreamController<int> sc = StreamController<int>(
onListen: () => print("Controller: the stream has been assigned a listener!"),
onCancel: () => print("Controller: the stream has been canceled!"),
// As you may notice, the event handlers are not executed every time the
// subscription gets paused or resumed.
//
// This behaviour comes from these facts:
// - Dart is single-threaded.
// - An event handler cannot be interrupted: once a Dart function starts
// executing, it continues executing until it exits. In other words, Dart
// functions can’t be interrupted by other Dart code.
// See https://webdev.dartlang.org/articles/performance/event-loop
// - A stream is a FIFO.
onPause: () => print("Controller: the stream has been paused!"),
onResume: () => print("Controller: the stream has been resumed!")
);
// Get the stream created by the stream controller.
// Right now, this stream has no assigned listener.
Stream<int> stream = sc.stream;
print("Does the stream provided by the controller have a listener ? ${sc.hasListener ? 'yes' : 'no'} - the answer should be no.");
// Push values into the stream controlled by the stream controller.
// Because no listener subscribed to the stream, these values are just stored
// into the stream.
for(int i=0; i<3; i++) {
print("Send the value ${i} into the stream.");
sc.add(i);
}
// Add a listener to the stream.
// Now the stream has an assigned listener.
StreamSubscription<int> subscriber = stream.listen(OnValueHandlerContainer.onValue);
OnValueHandlerContainer.setStreamSubscriber(subscriber);
subscriber.onDone(() => print("The subscription is done!"));
print("Does the stream provided by the controller have a listener ? ${sc.hasListener ? 'yes' : 'no'} - the answer should be yes.");
// Wait for 10 seconds.
print("Start waiting for 10 seconds");
Future.delayed(Duration(seconds: 10)).then((var v) => print("10 seconds ellapsed!"));
print("End of script");
}
结果:
Does the stream provided by the controller have a listener ? no - the answer should be no.
Send the value 0 into the stream.
Send the value 1 into the stream.
Send the value 2 into the stream.
Controller: the stream has been assigned a listener!
Does the stream provided by the controller have a listener ? yes - the answer should be yes.
Start waiting for 10 seconds
End of script
onValue: An event has been raised. The associated value is 0!
Pause the subscription. Wait for 1 second. Resume the subscription
Controller: the stream has been paused!
onValue: An event has been raised. The associated value is 1!
Pause the subscription. Wait for 1 second. Resume the subscription
onValue: An event has been raised. The associated value is 2!
Pause the subscription. Wait for 1 second. Resume the subscription
Controller: the stream has been resumed!
10 seconds ellapsed!
基本上,提供的代码执行以下操作:
onDone
”处理程序。OnValueHandlerContainer::onValue
)中,我们暂停并恢复订阅。流监听器按预期触发3次。
但是:
onDone
”处理程序从不执行。我希望它可以在脚本执行结束时执行,而控制器将被销毁(因此,订阅将被关闭)。onPause
”和“ onResume
”处理程序仅触发一次。我希望它们会被执行3次。有什么想法吗?
答案 0 :(得分:3)
没有收到“完成”事件的原因是,您永远不会close
进行流订阅。
您没有得到更多“暂停”事件的原因是流订阅是聪明。
您要做的第一件事是在没有人收听流之前添加很多事件。永远不要在真实代码中执行此操作,而应该仅在调用onListen
时开始添加事件,而在调用onPause
时再次停止事件,直到恢复订阅为止。
在这里,流订阅被塞满了许多事件,然后传递了一个事件,然后订阅被暂停。 订阅会尽职地将其报告回控制器。 然后订阅获得简历。这就是它变得聪明的地方。由于已经有要传递的事件,因此它不将履历表报告回控制器。实际上,它现在并不需要更多的事件,有很多事情要做。因此,它以一秒的间隔取消缓冲事件,直到缓冲区为空。在那个点,它将简历报告回控制器。
控制器报告工作已恢复,但是由于没有人再添加任何事件,也没有人调用close
,因此不会再发生任何事情。