Dart 中的事件循环和微任务(scheduleMicrotask)

Dart 应用程序有一个带有两个队列的事件循环 ------ 事件 队列微任务队列

Dart 程序的执行流程始于主 isolatemain 函数,然后可以通过隔离体机制创建和管理其他隔离体。每个子隔离体都可以有自己的入口点函数, 也就是耗时任务的函数。

事件循环和队列

在客户端应用中,主 isolate 的事件队列内,可能会包含重绘的请求、点击的通知或者(计时器、Dart 隔离之间的消息)其他界面事件。例如,下图展示了包含四个事件的事件队列,队列会按照先进先出的模式处理事件。

如下图所示,在 main() 方法执行完毕后,事件队列中的处理才开始,此时处理的是第一个重绘的事件。而后主 isolate 会处理点击事件,接着再处理另一个重绘事件。

下面这张图, 基本上可以表示事件模型。

当事件循环执行微任务队列中的任务时,事件队列会被卡住:应用程序无法绘制图形、处理鼠标单击、对 I/O 做出反应等。如下图所示。

在一个客户端应用中,耗时过长的同步操作,通常会导致 卡顿的动画。而最糟糕的是,应用界面可能完全失去响应。 这种情况, 我们可以考虑上一篇张讲的开启一个子isolate, 来处理耗时过长的同步任务。

main函数触发流程

main函数的触发是由_RawReceivePortImpl#_handleMessage 方法触发的:

_startMainIsolate

typescript 复制代码
/**
 * Takes the real entry point as argument and schedules it to run in the message
 * queue.
 */
@pragma("vm:entry-point", "call")
void _startMainIsolate(Function entryPoint, List<String>? args) {
  _delayEntrypointInvocation(entryPoint, args, null, true);
}

程序的实际入口点函数 _startMainIsolate 标记为 Dart VM 的入口点,并且通过调用 _delayEntrypointInvocation 函数来延迟执行入口点函数。这是 Dart VM 启动和执行 Dart 程序的一部分。

_delayEntrypointInvocation

scss 复制代码
void _delayEntrypointInvocation(Function entryPoint, List<String>? args,
    Object? message, bool allowZeroOneOrTwoArgs) {
  final port = RawReceivePort();
  port.handler = (_) { /// mark1 触发回调
    port.close();
    if (allowZeroOneOrTwoArgs) {
      if (entryPoint is _BinaryFunction) {
        (entryPoint as Function)(args, message);
      } else if (entryPoint is _UnaryFunction) {
        (entryPoint as Function)(args);
      } else {
        entryPoint();
      }
    } else {
      entryPoint(message);
    }
  };
  port.sendPort.send(null);
}

处理入口函数的延迟调用的。

  1. 创建一个 RawReceivePort 对象,这是 Dart 中用于在隔离体之间进行消息通信的一种机制。

  2. 为这个 RawReceivePort 对象设置一个事件处理器(handler),当接收到消息时,这个处理器会被触发。

  3. 在事件处理器中,首先关闭了这个 RawReceivePort,以确保它只能被触发一次。

main 函数的触发也涉及 消息通知机制_startIsolate 触发 _delayEntrypointInvocation 方法,其中创建 RawReceivePort 接收端看对象,并为 handler 赋值。

_startIsolate

javascript 复制代码
void _startIsolate(
    Function entryPoint, List<String>? args, Object? message, bool isSpawnUri) {
  _delayEntrypointInvocation(entryPoint, args, message, isSpawnUri);
}

触发main方法回调

也就是说收到消息,触发 _RawReceivePortImpl#_handleMessage 时,执行的 handler 就是 mark1 所示的函数。 tag2entryPoint() 方法就是 main 方法。

参考资料

Dart 中的并发

相关推荐
gnip5 分钟前
企业级配置式表单组件封装
前端·javascript·vue.js
一只叫煤球的猫1 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
excel2 小时前
Three.js 材质(Material)详解 —— 区别、原理、场景与示例
前端
掘金安东尼2 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手6 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法6 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku6 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode6 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu6 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu6 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript