异常处理与 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 zone,main函数就运行在这个zone中。换句话说,Dart 的所有代码都运行在一个叫做root zone的沙箱中,包括所有isolate中的main函数和spawned 函数。
All isolate entry functions (
mainor 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的一些配置,用于自定义一些行为,比如拦截日志输出、注册回调等等zoneValueszone 的私有数据,可通过实例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处理回调函数的Zoneparent该委托表示父Zone,通过它将操作转发给父Zonezone表示执行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”