Flutter中的异步执行策略

Posted eclipse_xu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter中的异步执行策略相关的知识,希望对你有一定的参考价值。

点击上方蓝字关注我,知识会给你力量

在Flutter中,如何执行一段延迟执行的异步代码?我们可以找到下面这些方法。

  • scheduleMicrotask

  • Future.microtask

  • Future

  • Future.delayed

  • Timer.run

  • WidgetsBinding.addPostFrameCallback

  • SchedulerBinding.addPostFrameCallback

你可能会说,这是相当多的选择,但是它们彼此之间有些什么异同呢?

Event Loop and Multithreading

Dart是一个单线程模型。但是你的Flutter应用同样可以同时做多件事情,这就是「Event Loop」发挥作用的地方。Event Loop是一个无尽的循环,它执行预定的events。这些events(或者只是代码块)必须是轻量级的,否则,你的应用程序会感觉卡顿。

每个event,如按下按钮或网络请求,都被安排在一个事件队列中,等待被事件循环捡起并执行。这种设计模式在UI和其他处理任何类型事件的系统中相当常见。

在Dart的单线程模型中,还有一个Microtask。它组成了Event Loop中的另一一个队列,即Microtask Queue。关于这个队列你唯一需要记住的是,在事件本身被执行之前,所有安排在Microtask Queue的任务都将在Event Loop循环的一次迭代中被执行。可以通过这个链接查看更多内容:https://dart.cn/articles/archive/event-loop

Events

任何进入event queue的东西都被称之为Event。这是Flutter中调度异步任务的默认方法。为了调度一个Event,我们把它添加到event queue中,由Event Loop来接收。这种方法被许多Flutter机制所使用,如I/O、手势事件、Timer等。

Timer

Timer是Flutter中异步任务的基础。它被用来安排event queue中的代码执行,无论是否有延迟执行的需要。由此产生的有趣的事实是,如果当前队列很忙,你的定时器将永远不会被执行,即使时间到了。

Timer.run(() 
    print("Timer");
);

Futureand Future.delayed

Future是Dart中使用的非常广泛的一个异步方法,它的内部实现,实际上也就是基于Timer的。

Future<void>(() 
    print("Future Event");
);

Future<void>.delayed(Duration.zero, () 
    print("Future.delayed Event");
);

它的内部实现如下。

Microtasks

如前所述,所有调度的microtasks都会在下一个调度的Event之前执行。建议避免使用这个队列,除非绝对需要异步执行代码,而且要在event queue的下一个事件之前处理。你也可以把这个队列看成是属于前一个事件的任务队列,因为它们将在下一个事件之前完成。如果这个队列不断膨胀,就会完全冻结你的应用程序,因为它必须先执行这个队列中的所有内容,然后才能进行其事件队列的下一次迭代,例如处理用户输入,甚至渲染应用程序本身。

scheduleMicrotask

顾名思义,在microtask queue中调度一个块代码。与Timer类似,如果出错,会使应用程序崩溃。

scheduleMicrotask(() 
    print("Microtask");
);

Future.microtask

与我们之前看到的类似,但它将我们的microtask包裹在一个try-catch块中,以一种漂亮而干净的方式返回执行结果或异常。

Future<void>.microtask(() 
    print("Microtask");
);

它的内部实现如下。

Post Frame Callback

前面两种方法只涉及到lower-level Event Loop,而现在我们要转到Flutter领域。这个Callback会在渲染管道完成时被调用,所以它与widget的生命周期相管理。当它被调度时,它只会被调用一次,而不是在每一帧都回调。使用addPostFrameCallback方法,你可以安排一个或多个回调,在界面渲染完成后被调用。

所有预定的Callback将在frame结束时按照它们被添加的顺序执行。到这个回调被调用的时候,可以保证Widget的构建过程已经完成。通过一些方法,你甚至可以访问Widget(RenderBox)的布局信息,比如它的大小,并做其他的一些事情。Callback本身将在正常的event queue中运行,Flutter默认使用该队列来处理几乎所有事情。

SchedulerBinding

这是一个负责绘图回调的mixin类,实现了我们感兴趣的方法。

SchedulerBinding.instance.addPostFrameCallback((_) 
    print("SchedulerBinding");
);

WidgetsBinding

我特意包括这个,因为它经常和SchedulerBinding一起被提及。它从SchedulerBinding中继承了这个方法,并有与我们的主题无关的一些额外方法。一般来说,你使用SchedulerBinding或WidgetsBinding并不重要,两者将执行位于SchedulerBinding中的完全相同的代码。

WidgetsBinding.instance.addPostFrameCallback((_) 
    print("WidgetsBinding");
);

总结

由于我们今天学到了很多理论知识,我强烈建议大家多玩一会儿,以确保我们能正确地掌握它。我们可以在之前的initState中使用下面的代码,并尝试预测它将以何种顺序被执行,这并不是一件看起来很容易的事情。

SchedulerBinding.instance.addPostFrameCallback((_) 
  print("SchedulerBinding");
);

WidgetsBinding.instance.addPostFrameCallback((_) 
  print("WidgetsBinding");
);

Timer.run(() 
  print("Timer");
);

scheduleMicrotask(() 
  print("scheduleMicrotask");
);

Future<void>.microtask(() 
  print("Future Microtask");
);

Future<void>(() 
  print("Future");

  Future<void>.microtask(() 
    print("Microtask from Event");
  );
);

Future<void>.delayed(Duration.zero, () 
  print("Future.delayed");

  Future<void>.microtask(() 
    print("Microtask from Future.delayed");
  );
);

输出结果如下所示。

I/flutter (31989): scheduleMicrotask
I/flutter (31989): Future Microtask
I/flutter (31989): SchedulerBinding
I/flutter (31989): WidgetsBinding
I/flutter (31989): Timer
I/flutter (31989): Future
I/flutter (31989): Microtask from Event
I/flutter (31989): Future.delayed
I/flutter (31989): Microtask from Future.delayed

现在我们了解了这么多细节,你可以对如何安排你的代码做出深思熟虑的决定。作为一个经验法则,如果你需要你的上下文或与Layout或UI相关的东西,请使用addPostFrameCallback。在任何其他情况下,用Future或Future.delayed在标准的event queue中进行调度应该是足够的。microtask queue是非常小众的东西,你可能永远不会遇到,但它仍然值得了解。当然,如果你有一个繁重的任务,你就会考虑创建一个Isolate。

翻译自——https://oleksandrkirichenko.com/blog/delayed-code-execution-in-flutter/

向大家推荐下我的网站 https://www.yuque.com/xuyisheng  点击原文一键直达

专注 android-Kotlin-Flutter 欢迎大家访问

往期推荐

本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。

< END >

作者:徐宜生

更文不易,点个“三连”支持一下👇

以上是关于Flutter中的异步执行策略的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 的异步机制Future

Flutter进阶篇(4)-- Flutter的Future异步详解

flutter入门之dart中的并发编程异步和事件驱动详解

flutter入门之dart中的并发编程异步和事件驱动详解

Flutter延时任务Flutter通过Future与Timer实现延时任务

在 dart/flutter 中执行多次从 firestore 获取数据的异步函数