通过Tree shaking和deferred loading来优化Flutter Web应用程序的性能
为了获得最佳的用户体验,应用程序的加载速度非常重要。Flutter Web应用程序的初始加载时间可以通过最压缩其JavaScript包的大小缩短。Dart编译器包含诸如Tree shaking和deferred loading(延迟加载)之类的功能,它们都可以压缩JavaScript。本文介绍了它们的工作方式以及如何在应用程序中使用它们。
默认情况下的Tree shaking
编译Flutter Web应用程序时,JavaScript由dart2js编译器生成。发布版本具有最高级别的优化,其中包括通过tree shaking删除无用代码。
Thee shaking是消除无效代码的过程,只包含会被执行的代码。这意味着您无需担心应用程序包含的库的大小,因为未使用的类或函数将从已编译的JavaScript包中排除。
我们来看一个tree shaking示例:
-
创建一个dart文件
greeter.dart
:abstract class Greeter { String greet(String name); } class EnglishGreeter implements Greeter { String greet(String name) => 'Hello $name!'; } class SwedishGreeter implements Greeter { String greet(String name) => 'Hej $name!'; } void main() { print(EnglishGreeter().greet('World')); }
-
在您的终端中运行dart2js -O4 greeter.dart,然后查看生成的输出out.js。
在生成的JavaScript代码中,没有任何对SwedishGreeter类的引用,也没有任何字符串Hej $ name的引用,因为在编译器tree shaking时已将其删除。编译器只能通过静态分析找出哪些代码可以访问,哪些是不会被访问的代码。
以以下示例为例,其中根据系统区域设置定义了问候语:
Locale locale = Localizations.localeOf(context); if (locale.languageCode == 'sv') { greeter = SwedishGreeter(); } else { greeter = EnglishGreeter(); }
编译器不知道用户的系统区域设置,因此EnglishGreeter和SwedishGreeter都包含在JavaScript包中。对于此类用例,deferred loading可以帮助减小初始js包大小。
仅在需要时才使用延迟加载来加载代码
Deferred loading,也称为lazy loading(惰性加载),允许您在需要时加载库。如果应用程序中有很多不是很常用的功能,适合使用延迟加载。请注意,延迟加载是dart2js功能,因此不适用于Flutter移动应用程序。下面是个简单的例子,将导入的程序包或文件标记为deferred,然后等待其加载后再使用:
import 'greeter.dart' deferred as greeter;
void main() async {
await greeter.loadLibrary();
runApp(App(title: greeter.EnglishGreeter().greet('World')));
}
编译此代码将生成两个JavaScript文件。在延迟导入上调用loadLibrary时,它将加载greeter库。
在Flutter(一切都widget)中,您可能要使用FutureBuilder。widget的构建方法是同步的,因此您不能在build方法内部的loadLibrary上调用await。但是,您可以在build方法中返回FutureBuilder,也可以在加载库时使用它来显示不同的UI:
import 'greeter.dart' deferred as greeter;
FutureBuilder(
future: greeter.loadLibrary(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(greeter.greet('World'));
} else {
return Text('Loading...');
}
},
)
要自己尝试(请参阅GitHub上的完整示例),请打开Chrome DevTools并单击“网络”标签以查看网络请求。重新加载页面以查看何时加载和导入库。在以下屏幕快照中,延迟了main.dart.js_1.part.js文件的加载:
在Flutter Gallery中延迟加载本地化版本
Flutter Gallery支持70多种语言,但大多数用户只使用一种。延迟加载本地化字符串是此功能的一个很好的用途。例如,在Flutter Gallery中实施了本地化字符串的延迟加载后,该应用程序的初始JavaScript包大小减少了一半。如果Flutter Web应用程序中有很多本地化字符串,请考虑延迟加载这些文件。gen_l10n.dart脚本为此包含标志--use-deferred-loading(当前仅在1.19 SDK master channel可用)。
这篇文章是关于我们在提高Flutter Gallery性能时所学知识的系列文章的一部分。我希望您发现它有用,并且您学到了一些可以应用于Flutter Web应用程序的知识!