我试图展示angulardart的进展,并认为Future会对此有所帮助。但是后来我意识到,Future必须递归显示进度,因为Future会立即返回,然后执行冗长的操作。
如果我创建一个Future,该Future会在满足最终条件之前进行自我调用,它将与进度条一起使用。但是我认为这不是一个很好的做法,因为这些调用每次递归都会增加堆栈上的内存。只需考虑遍历10亿个数据集的循环,这些循环可能要运行几个小时,而每个循环都在当前Future中调用一个新的Future。
是否有更好的方法来创建需要一定时间才能在每个元素上工作的循环(包括调用必须异步完成的网站并评估返回值)?在循环过程中,用户应该看到一个进度,显示“ x / 1000000完成”。
我认为必须使用Future来完成,因为UI需要在启动循环后重新加载,但是对我而言,递归Future似乎是个坏主意。
答案 0 :(得分:2)
由于它是一个单线程平台,因此您需要将来立即在Web上返回给您。如果异步操作在完成之前没有返回,那么您将挂起浏览器,这对用户来说不是很好的体验。
相反,您有两种选择:
Dart具有使未来与await关键字同步的能力。因此,您可以执行以下操作:
void performAction() async {
showProgress = true;
await expensiveRpc();
showProgress = false;
}
这将要求进度处于中间状态,因为您实际上并没有在更新进度条。就是说,如果您真的没有从RPC中获取进度事件,那么这可能是更好的解决方案。
现在,如果您的RPC或操作为您提供了一些反馈,那么您可以对流进行一些改进。
void performAction() {
showProgress = true;
expensiveRpc().listen((progress) {
if (progress.done) {
showProgress = false;
} else {
percentComplete = progress.value;
});
}
确实,它更多地取决于您与之交互的RPC或服务,而不是如何更好地更新进度而不是进度本身。
答案 1 :(得分:0)
与此同时,我认识到Future方法会立即返回,而无需在方法主体中执行任何操作。因此,解决方案非常简单:
只需用Future声明rpc,在方法中执行您需要做的任何事情,并且在调用它时,请使用then(...)完成收集数据后需要做的事情。
int progress = 0;
int progressMax = 100;
bool progressCanceled = false;
Future rpc(var data)
async{
for(progress=0; progress<progressMax, progress++)
{
// do whatever you need to do with data
if(progressCanceled)
return;
}
}
rpc(data).then(
{
if(progressCanceled)
return;
// do whatever is needed after having received that data
});
rpc被执行,并且在rpc执行rpc必须执行的操作的同时,调用过程可以继续。主程序可以处理按钮单击以将progressCanceled设置为true,并且rpc方法将询问状态并停止处理(如果已设置)。