异常处理与 Zone

同步异常的处理

如果关心具体异常,针对不同异常进行不同处理,可以使用try...on处理异常,finally是可选的,用于最后的处理。

  try {
      // 使除数为0
      print(11~/0);
  } on IntegerDivisionByZeroException {
      print("除数为0");
  }on Exception{
      print("Exception");
  }finally {
      print("finally");
  }

不关心具体异常,只想捕获,避免异常继续传递,则可以使用try...catch处理

  try {
      print(11~/0);
  } catch(e){
      // 打印报错信息
      print(e);
  }finally {
      print("finally");
  }

如果想获取更多异常信息,可以使用两个参数的catch,第二个参数是异常的调用栈信息

  try {
      print(11~/0);
  } catch(e,s){
      print(s);
  }

如果你既想针对不同异常进行不同处理,还想打印调用栈信息,那就将两种结合起来使用

  try {
      print(11~/0);
  } on IntegerDivisionByZeroException catch(e,s){
      print(s);
  } on Exception catch(e,s){
      print(s);
  }

异步异常的处理

在Dart中处理异步异常可以使用三种方式,一种是调用异步方法时使用await,然后再使用try/catch捕获,另一种是使用Future 的 API,即通过catchError来捕获。最后一种则是使用Zone

什么是Zone?

它基本上就是一个异步操作的执行上下文,在错误处理和分析时非常有用。更简单说,它就是一个沙箱环境,可以使函数在这个沙箱环境中执行。

Dart中有一个runZoned()方法,可以给执行对象指定一个Zone。不同Zone之间是隔离的,这些沙箱可以捕获、拦截或修改一些代码行为,如Zone中可以捕获日志输出、Timer创建、微任务调度的行为,同时Zone也可以捕获所有未处理的异常。

简单示例

void main() async{
   runZoned((){
     Future(() { throw "asynchronous error"; });
   },onError: (Object o, StackTrace st){
     print(o);
     print(st);
   });
}

Zone的使用

在Dart 全局中有一个root zonemain函数就运行在这个zone中。换句话说,Dart 的所有代码都运行在一个叫做root zone的沙箱中,包括所有isolate中的main函数和spawned 函数。

All isolate entry functions (main or spawned functions) start running in the root zone (that is, [Zone.current] is identical to [Zone.root] when the entry function is called).

  // 将一个函数放在root zone中执行
  Zone.root.run((){
    print("root run");
  });

  // 从当前的zone创建一个新的zone
  Zone myZone = Zone.current.fork();
  myZone.run((){
    print("myZone run");
  });

仅仅在root zone中运行函数似乎意义不大,当我们需要做一些更高级的操作时,就需要使用fork函数从已有的zone创建一个新的子zone,这有些类似于从父zone继承。

// fork函数原型
Zone fork({ZoneSpecification specification, Map zoneValues});
  • specification:zone的一些配置,用于自定义一些行为,比如拦截日志输出、注册回调等等
  • zoneValues zone 的私有数据,可通过实例zone[key]方式获取,这些数据可以被子zone继承。
  Zone myZone = Zone.current.fork(zoneValues: {"a":1});
  myZone.run(()=>print("myZone run"));
  // 在子Zone中访问父Zone中的数据
  Zone childZone = myZone.fork();
  childZone.run(()=>print(childZone["a"]));
void main() async{
  Zone myZone = Zone.current.fork(
    specification:ZoneSpecification(
      // 处理回调
      registerCallback: <R>(self, parent, zone, f) {
        f();
        return f;
      },

      // 处理run函数中执行的任务
      run:<R>(self, parent, zone, f) {
        print("Enter the run method");
        return parent.run(zone, f); 
      }));

  // 在zone中执行任务
  myZone.run((){
    // 注册回调
    Zone.current.registerCallback(()=>print("callback start"));
    print("myZone run task...");
    Zone.current.registerCallback(()=>print("callback end"));
  });
}

输出结果:

Enter the run method
callback start
myZone run task...
callback end

拦截并修改print函数的行为

void main() async{
    Zone myZone = Zone.current.fork(
    specification:ZoneSpecification(
      //拦截并修改 print 函数的输出
      print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
        parent.print(zone, "test info: $line");
      },

      // 处理未捕获的异常
      handleUncaughtError: (Zone self,ZoneDelegate parent, Zone zone, Object error, StackTrace stackTrace){
        print(error);
    }));

  myZone.run((){
    // 打印一句话
    print("myZone run task...");
    // 生成一个异步错误
    Future.error("generate error");
  });
}

输出结果:

test info: myZone run task...
test info: generate error

在Dart中可以使用runZoned函数简化编写,其原型如下

R runZoned<R>(R body(),
    {Map zoneValues, ZoneSpecification zoneSpecification, Function onError})

简化示例

  runZoned((){
      print("myZone run task...");
      Future.error("generate error");
    },
    zoneSpecification: ZoneSpecification(
      print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
        parent.print(zone, "test info: $line");
      },

      handleUncaughtError: (Zone self,ZoneDelegate parent, Zone zone, Object error, StackTrace stackTrace){
        print(error);
    }));

关于拦截器中的参数

  • self 处理回调函数的Zone

  • parent 该委托表示父Zone,通过它将操作转发给父Zone

  • zone 表示执行run操作的 zone。很多操作需要明确该操作是在哪个Zone中被调用

总结

Dart中的Zone除了可以处理异常,更重要的是它还提供了Hook机制,可用于对代码进行性能分析等。

主要提供了下列功能

  • Fork子分区处理
  • 在分区中注册和运行回调函数
  • 调度Microtask微任务和Timer定时器
  • 处理未捕获的异步类型的异常
  • Print 输出处理

查看ZoneSpecification的构造函数即可知

  const factory ZoneSpecification(
      {HandleUncaughtErrorHandler handleUncaughtError,
      RunHandler run,
      RunUnaryHandler runUnary,
      RunBinaryHandler runBinary,
      RegisterCallbackHandler registerCallback,
      RegisterUnaryCallbackHandler registerUnaryCallback,
      RegisterBinaryCallbackHandler registerBinaryCallback,
      ErrorCallbackHandler errorCallback,
      ScheduleMicrotaskHandler scheduleMicrotask,
      CreateTimerHandler createTimer,
      CreatePeriodicTimerHandler createPeriodicTimer,
      PrintHandler print,
      ForkHandler fork})

公众号“编程之路从0到1”

20190301102949549

Copyright © Arcticfox 2020 all right reserved,powered by Gitbook文档修订于: 2024-06-09 20:22:55

results matching ""

    No results matching ""