原文地址:devblogs.microsoft.com/oldnewthing…
原文作者:devblogs.microsoft.com/oldnewthing…
发布时间:2019年5月2日
被称为Async-Async的功能通过假装异步操作在实际开始之前就开始了,使得异步操作更加异步。正如我在前面所提到的,如果你一直在违反规则并逍遥法外,你可能会注意到其中的不同。我们上次看到,如果你突变了一个传递给异步方法的参数,会发生什么。简短的回答是:在异步方法完成之前不要这么做)。
另一个你可能会注意到差异的地方是,如果你的多个调用相互竞赛。
// Queue two animations in sequence.
// Queue the first animation.
var task1 = widget.QueueAnimationAsync(source1, curve1);
// Queue the second animation.
var task2 = widget.QueueAnimationAsync(source2, curve2); // wrong
// Wait for the tasks to complete.
await Task.WhenAll(task1, task2);
这段代码 "知道 "Widget.QueueAnimationAsync方法在返回之前会选择添加动画的时间点,然后再使用IAsyncOperation。因此,它 "知道 "可以依次启动QueueAnimationAsync操作,并等待两个项目完成,从而依次排队。
当Async-Async被启用时,这段代码无法工作,因为对Widget.QueueAnimationAsync的两次调用不需要在服务器上按照客户端发出的相同顺序启动。假的AsyncOperation在服务器上发出启动操作的请求,但不等待服务器确认操作的启动。如果你启动了两个操作,它们就会争先恐后地到达服务器,而第二个操作可能会先到达服务器,在这种情况下,服务器上的操作将以相反的顺序启动。
当然,正确的客户端代码本来就不应该对异步操作的顺序有这种依赖性。毕竟,服务器可能会在异步操作的后期才决定选择动画的位置,而第二个操作可能会比第一个操作提前跑到决策点。例如,QueueAnimationAsync的内部行为可能已经是
- 从源和曲线参数创建一个新的动画。
- 将该动画添加到动画列表中。
如果你同时启动两个QueueAnimationAsync操作,你并不知道哪一个会先到达步骤2。
如果排队的顺序很重要,那么你需要等到第一个动画肯定排队后再排队第二个。你必须以串联而不是并行的方式运行这些操作。
// Queue two animations in sequence.
// Queue the first animation.
await widget.QueueAnimationAsync(source1, curve1);
// Queue the second animation.
await widget.QueueAnimationAsync(source2, curve2); // important
在某种意义上,这又是一个 "突变传递给异步方法的参数 "的案例。被突变的参数是widget本身! 好吧,更具体地说,是widget的动画队列。
下一次,我们将看看Async-Async的另一个后果,如果你一直在欺骗规则,你可能会注意到。