如何 运行 多个异步函数,以便它们被调用(先进先出?)
How to run multiple async functions in order they were called (FIFO?)
我花了很多时间寻找解决方案,但由于我是 Dart 初学者,我无法自己找到它。
我想要实现的是在应用程序 运行ning 时从代码中的不同点为一些随机调用的异步函数(比方说,当用户点击我的应用程序中的按钮时)创建类似队列的东西.我希望它们按照调用的顺序执行,所以基本上我有异步方法,例如 updateDate() 和 updatePoints() 以及何时用户正在点击按钮 X,updateDate() 将被调用(添加到队列),与 Y 和 updatePoints() 类似。当用户点击 i 时。 e. X, X, Y 我想 运行 updateDate(), updateDate(), updatePoints() 这个确切的顺序。当一项任务完成时,另一项任务即将开始。我想我不能使用 await 来实现这一点。任何提示将不胜感激!
import 'dart:async';
import 'dart:collection';
import 'dart:math';
Future<void> main() async {
_simulateRealWork();
}
Scheduler _scheduler = Scheduler();
class Scheduler {
bool _scheduled = false;
Queue<Future Function()> _queue = Queue<Future Function()>();
void schedule(Future Function() task) {
_queue.add(task);
if (!_scheduled) {
_scheduled = true;
Timer(Duration(seconds: 0), _execute);
}
}
Future _execute() async {
while (true) {
if (_queue.isEmpty) {
_scheduled = false;
return;
}
var first = _queue.removeFirst();
await first();
}
}
}
void _simulateRealWork() {
var maxPeriod = 5;
var count = 5;
for (var i = 0; i < count; i++) {
print('Timer $i');
var random = Random();
Timer(Duration(seconds: random.nextInt(maxPeriod)), () {
print('Scheduled work $i');
Future work() async {
print('Started work $i');
await Future.delayed(Duration(seconds: random.nextInt(maxPeriod)));
print('Ended work $i');
}
_scheduler.schedule(work);
});
}
}
结果:
Timer 0
Timer 1
Timer 2
Timer 3
Timer 4
Scheduled work 2
Started work 2
Scheduled work 0
Scheduled work 3
Ended work 2
Started work 0
Scheduled work 1
Scheduled work 4
Ended work 0
Started work 3
Ended work 3
Started work 1
Ended work 1
Started work 4
Ended work 4
以下代码在大型任务队列中使用时可能是一种不好的做法,但如果您确定任务数组不会超过足够的大小 - 这可能会很好地工作:
Future<List<T>> runOneByOne<T>(List<T Function()> list) {
if (list.isEmpty) {
return Future.value(null);
}
Future task = Future<T>.microtask(list.first);
final List<T> results = [];
for (var i = 1; i < list.length; i++) {
final func = list[i];
task = task.then((res) { results.add(res); return Future<T>.microtask(func); });
}
return task.then((res) { results.add(res); return results; });
}
它通过将一个 Future
包装到另一个来按原始顺序一个接一个地执行函数。 results
数组用于存储 returned 值,最后 returning 所有值。
如果遇到错误,执行将停止并抛出。在这种情况下,结果数组会丢失。您可以将 try {...}
闭包添加到每个 microtask
包装器以忽略错误,并在该特定任务中添加 return null
,在 results
数组中保留其他值。
用法示例:
runOneByOne<int>([
() { print("First"); return 1; },
() { print("Second"); return 2; },
() { print("Third"); return 3; },
]).then((results) {
print(results); // List<int> [ 1, 2, 3 ]
});
我花了很多时间寻找解决方案,但由于我是 Dart 初学者,我无法自己找到它。 我想要实现的是在应用程序 运行ning 时从代码中的不同点为一些随机调用的异步函数(比方说,当用户点击我的应用程序中的按钮时)创建类似队列的东西.我希望它们按照调用的顺序执行,所以基本上我有异步方法,例如 updateDate() 和 updatePoints() 以及何时用户正在点击按钮 X,updateDate() 将被调用(添加到队列),与 Y 和 updatePoints() 类似。当用户点击 i 时。 e. X, X, Y 我想 运行 updateDate(), updateDate(), updatePoints() 这个确切的顺序。当一项任务完成时,另一项任务即将开始。我想我不能使用 await 来实现这一点。任何提示将不胜感激!
import 'dart:async';
import 'dart:collection';
import 'dart:math';
Future<void> main() async {
_simulateRealWork();
}
Scheduler _scheduler = Scheduler();
class Scheduler {
bool _scheduled = false;
Queue<Future Function()> _queue = Queue<Future Function()>();
void schedule(Future Function() task) {
_queue.add(task);
if (!_scheduled) {
_scheduled = true;
Timer(Duration(seconds: 0), _execute);
}
}
Future _execute() async {
while (true) {
if (_queue.isEmpty) {
_scheduled = false;
return;
}
var first = _queue.removeFirst();
await first();
}
}
}
void _simulateRealWork() {
var maxPeriod = 5;
var count = 5;
for (var i = 0; i < count; i++) {
print('Timer $i');
var random = Random();
Timer(Duration(seconds: random.nextInt(maxPeriod)), () {
print('Scheduled work $i');
Future work() async {
print('Started work $i');
await Future.delayed(Duration(seconds: random.nextInt(maxPeriod)));
print('Ended work $i');
}
_scheduler.schedule(work);
});
}
}
结果:
Timer 0
Timer 1
Timer 2
Timer 3
Timer 4
Scheduled work 2
Started work 2
Scheduled work 0
Scheduled work 3
Ended work 2
Started work 0
Scheduled work 1
Scheduled work 4
Ended work 0
Started work 3
Ended work 3
Started work 1
Ended work 1
Started work 4
Ended work 4
以下代码在大型任务队列中使用时可能是一种不好的做法,但如果您确定任务数组不会超过足够的大小 - 这可能会很好地工作:
Future<List<T>> runOneByOne<T>(List<T Function()> list) {
if (list.isEmpty) {
return Future.value(null);
}
Future task = Future<T>.microtask(list.first);
final List<T> results = [];
for (var i = 1; i < list.length; i++) {
final func = list[i];
task = task.then((res) { results.add(res); return Future<T>.microtask(func); });
}
return task.then((res) { results.add(res); return results; });
}
它通过将一个 Future
包装到另一个来按原始顺序一个接一个地执行函数。 results
数组用于存储 returned 值,最后 returning 所有值。
如果遇到错误,执行将停止并抛出。在这种情况下,结果数组会丢失。您可以将 try {...}
闭包添加到每个 microtask
包装器以忽略错误,并在该特定任务中添加 return null
,在 results
数组中保留其他值。
用法示例:
runOneByOne<int>([
() { print("First"); return 1; },
() { print("Second"); return 2; },
() { print("Third"); return 3; },
]).then((results) {
print(results); // List<int> [ 1, 2, 3 ]
});