Dart:runZoned与async/await的代码实现差异探究
除了你已经了解的Zone本地值和代码追踪能力,这两段代码的核心差异主要体现在错误捕获范围和异步任务错误兜底能力上:
错误捕获的覆盖范围不同
第一段用runZoned的代码,其onError回调会捕获整个Zone范围内所有未被局部处理的异步错误——包括server.listen回调中处理HTTP请求时抛出的异常(比如静态文件读取失败、请求处理逻辑出错)。
而第二段的try/catch仅能捕获await HttpServer.bind()过程中产生的错误,server.listen启动的Stream监听逻辑里的异步错误(比如请求处理时的异常)完全不在try/catch的覆盖范围内,这些错误会直接成为未处理的异步错误导致程序崩溃。错误处理的兜底逻辑不同
runZoned的onError相当于给Zone内所有异步任务设置了一个全局兜底的错误处理器,只要任务在Zone内启动,无论嵌套多少层异步调用,未被局部try/catch捕获的错误都会流向这个兜底处理器。
而try/catch是局部的错误捕获,仅对包裹的同步代码和await的异步操作生效,后续独立的异步任务(比如Stream的监听)不在其管辖范围内。错误栈的完整性差异
runZoned会保留异步任务在Zone上下文中的调用栈信息,onError参数里的stackTrace能完整追踪到错误发生的异步调用链路;而第二段代码中catch块里的e.stackTrace无法完整捕获后续异步任务的调用栈(比如server.listen回调里的错误栈不会被包含)。
举个具体场景:如果staticFiles.serveRequest处理请求时抛出异常,第一段代码的onError会捕获并打印错误和栈信息;而第二段代码会直接触发未处理的异步错误,导致程序终止。
内容的提问来源于stack exchange,提问作者Guy

