当前位置: 首页 > Web前端 > HTML

Typescript表现

时间:2023-03-28 19:13:58 HTML

原文:https://github.com/microsoft/...斗皮粉们,我们又见面了。今天一期是由字节跳动数据平台“StoneyAllen”翻译的一篇文章《typescript性能》。在2020年倒计时的最后几天,祝大家新年快乐~,农民工,农民工~。让我们开始仔细阅读吧!译者:StoneyAllen有一些简单的Typescript配置,可以让你获得更快的编译和编辑体验。这些方法越早掌握越好。除了最佳实践之外,下面列出了一些用于调查缓慢编译/编辑体验的常用技术,以及一些作为帮助TypeScript团队调查问题的最后手段的常用方法。编写易于编译的代码以首先使用接口而不是交集类型。很多时候,简单对象类型的类型别名与接口非常相似。但是,只要你需要定义两种或多种类型,你就可以使用接口来扩展这些类型,或者在类型别名中将它们相交,这时区别就很明显了。由于该接口定义了单一平面对象类型,因此可以检测到属性冲突并且有必要解决这些冲突。另一方面,交集类型只是递归合并的属性,在某些情况下它永远不会产生。接口表现一致,而交叉类型定义的类型别名不会出现在其他交叉类型上。接口之间的类型关系也被缓存,而不是整个交集类型。最后一个值得注意的区别是,在交集类型的情况下,在检查“有效”/“扁平化”类型之前检查所有属性。因此,建议在创建交集类型时使用带有接口/扩展的扩展类型。添加类型注释,尤其是返回类型,使用类型注释可以为编译器节省大量工作。这是因为命名类型比匿名类型(编译器更喜欢匿名类型)更简洁,从而减少了读取和写入声明文件所花费的时间。虽然类型推断非常方便,但没有必要在任何地方都这样做。但是,如果您知道代码的缓慢部分,它可能会有用。比联合类型更喜欢基类型联合类型很棒——它们允许你表达一个类型的可能值的范围。但它们也有一定的成本。每次将参数传递给printSchedule时,都需要比较联合类型中的每个元素。对于由两个元素组成的联合类型,这是微不足道的。但是,如果您的联合类型有很多元素,这将导致编译速度问题。比如去除union类型的冗余部分,需要成对比较元素,工作量呈二次方增长。当大量的union类型交集在一起时会出现这种检查,导致大量的类型交集在每个union类型上,需要减少这种情况的发生。避免这种情况的一种方法是使用子类型而不是联合类型。一个更现实的例子是在定义每个内置DOM元素的类型时。在这种情况下,更优雅的方法是创建一个包含所有元素的HtmlElement基类型,包括DivElement、ImgElement等。使用继承而不是创建无限多个联合类型DivElement|/*...*/|图片元素|/*...*/。使用项目引用在使用TypeScript构建内容密集型代码时,将代码库组织到几个独立的项目中会很有用。每个项目都有自己的tsconfig.json,可能会依赖于其他项目。这有利于避免在一次编译中导入太多文件,也可以更轻松地组合某些代码库布局策略。有一些非常基本的方法可以将代码库分解为多个项目。例如,一段程序代码,一部分用作客户端,一部分用作服务器,一部分由其他两个测试共享,也可以分解到自己的项目中。一个常见的问题是“一个项目应该有多大?”。这很像问“一个函数应该有多大?”或“一个班级应该有多大?”,在很大程度上取决于经验。一个熟悉的JS/TS代码拆分方法是使用文件夹。作为一种启发式方法,如果它们足够相关以至于位于同一个文件夹中,那么它们就属于同一个项目。除此之外,避免非常大或非常小的项目。如果一件物品比所有其他物品加起来还大,那就是一个警告信号。此外,最好避免拥有数十个单文件项目,因为这也会增加开销。您可以在此处阅读有关项目参考配置的更多信息。tsconfig.json或jsconfig.jsonTypeScript和JavaScript用户可以使用tsconfig.json文件任意配置编译方式。JavaScript用户还可以使用jsconfig.json文件配置自己的编辑体验。指定文件你应该始终确保你的配置文件不包含太多文件在tsconfig.json中,有两种方法可以在你的项目中指定文件。文件列表包括和排除列表。两者之间的主要区别在于files需要一个源文件。文件路径列表,包括/排除使用通配符模式来匹配文件。虽然指定文件可以让TypeScript直接快速地加载文件,但是如果你的项目中有很多文件,而不是只有几个顶级条目,那会很麻烦。此外,很容易忘记将新文件添加到tsconfig.json,这意味着您最终可能会遇到奇怪的编辑器行为,这些新文件被错误地解析,这可能很棘手。include/exclude有助于避免指定这些文件,但代价是:必须通过包含的目录发现这些文件。当运行大量文件夹时,这会减慢编译速度。此外,有时编译会包含很多不必要的.d.ts文件和测试文件,这会增加编译时间和内存开销。最后,虽然exclude有一些合理的默认值,但某些配置如mono-repos意味着像node_modules这样的“重”文件夹仍然可以被包含在内。对于最佳实践,我们建议如下:在您的项目中仅指定输入文件夹(即您希望将其源包含在编译/分析中的文件夹)并且不要将来自其他项目的源文件混合在同一文件夹中如果您将测试放在与其他源文件相同的文件夹,给它们一个不同的名称,这样它们就可以很容易地被排除,避免源目录中的大型构建工件和依赖文件夹,如node_modules注意:如果没有排除列表,默认情况下会排除node_modules;添加node_modules后,必须将node_modules显式添加到列表中。下面是一个合理的tsconfig.json演示了这个操作这是为了在使用像Node.js、Jasmine、Mocha、Chai等工具/包时使某些东西“工作”,因为这些工具/包没有被导入——它们只是被加载到全局环境中。有时这种逻辑会在编译和编辑场景下拖慢程序的构建时间,甚至会导致多个全局包的声明之间发生冲突,导致类似下面的问题。当不需要全局包时,修复方法很简单,只要在tsconfig.json/jsconfig.json中为“type”选项指定一个空字段即可。如果您仍然需要一些全局包,请将它们添加到类型字段增量项目输出--incremental标志允许TypeScript将上次编译的状态保存到.tsbuildinfo文件中。该文件用于计算自上次运行以来可能已重新检查/重新输出的最小文件集,就像TypeScript的--watch模式一样。为项目引用使用复合标志时,默认情况下会启用增量编译,但这会提供相同的速度提升。跳过.d.ts检查默认情况下,TypeScript会对项目中的所有.d.ts文件执行彻底检查,以发现问题或不一致;但是,这种检查通常是不必要的。大多数时候,.d.ts文件是已知如何工作的——类型相互扩展的方式已经被验证过一次,重要的声明仍然被检查。TypeScript提供了使用skipDefaultLibCheck标志跳过.d.ts文件(如lib.d.ts)的类型检查的选项此外,您还可以启用skipLibCheck标志以跳过编译中的所有.d.ts文件.此选项通常会隐藏.d.ts文件中的错误配置和冲突,因此仅建议在快速构建场景中使用它们。狗的列表是使用更快差异检查的动物列表吗?也就是说,List是否可以分配给List?一种直接的查找方法是逐个成员类型结构比较。不幸的是,这可能会带来昂贵的性能开销。但是,如果我们对List有足够的了解,我们可以简化此可分配性检查以确定Dog是否可分配给Animal(即无需考虑List的每个成员)。特别是当我们需要知道类型参数T的区别时。仅当启用strictFunctionTypes标志时,编译器才能充分利用这种潜在的加速(否则,它会使用更慢但更宽松的结构检查)。因此,我们建议使用--strictFunctionTypes进行构建(在--strict下默认启用)以配置其他构建工具。TypeScript编译通常与其他构建工具一起执行——尤其是在编写可能涉及打包器的Web应用程序时。虽然我们只能对一些构建工具提出建议,但理想情况下这些技术可以得到广泛应用。确保除了阅读本节之外,您还阅读了有关所选构建工具的性??能的信息-例如:ts-loader的FasterBuilds部分awesome-typescript-loader的性能问题部分并行类型检查类型检查通常需要从其他文件加载与转换/输出代码等其他步骤相比,类型检查可能相对昂贵。因为类型检查可能需要更多时间,它可能会影响内部开发循环——换句话说,你可能会经历更长的编辑/编译/运行周期,这可能会让你头疼。出于这个原因,一些构建工具可以在一个单独的进程中运行类型检查而不会阻塞输出。虽然这意味着在TypeScript构建和错误报告发生之前有死代码在运行,但通常首先在编辑器中看到错误,而不会长时间阻止运行工作代码。一个实际的例子是Webpack的一个分支——ts-checker-webpack-plugin插件,或者awesome-typescript-loader有时也会这样做。隔离文件输出默认情况下,TypeScript输出需要可能不是本地文件的语义信息。这是为了了解如何导出const枚举和命名空间等功能。但是需要检查其他文件才能生成某个文件,这会减慢输出速度。需要非本地信息的功能需求相对较少——可以使用常规枚举代替常量枚举,可以使用模块代替命名空间。出于这个原因,TypeScript提供了isolatedModules标志来报告由非本地信息驱动的函数的错误。启用isolatedModules意味着您的代码库对于使用TypeScriptAPI(如transpileModule)或替代编译器(如Babel)的工具是安全的。例如,以下代码在使用隔离文件转换的运行时无法正常工作,因为常量枚举值应该被内联;幸运的是,isolatedModules会很早就告诉我们这一点,请记住:isolatedModules不会自动使代码生成速度更快-它只是告诉您您将要使用可能不受支持的功能。你想要的是不同构建工具和API中独立模块的输出。您可以使用以下工具影响独立文件的输出。提供了一个transpileOnly标志,通过使用transpileModule执行独立的文件输出TypeScript可以直接使用transpileModuleAPIawesome-typescript-loader提供了useBabel标志babel-loader以单独的方式编译文件(但不提供类型检查)当gulp-typescript启用时isolatedModules,可以实现独立文件输出rollup-plugin-typescript只执行独立文件编译ts-jest可以使用(isolatedModules标志设置为true)isolatedModules为truets-node可以检测“ts-node”中的“transpileOnly”选项tsconfig.json的字段,也有一个--transpile-only标志。调查问题有一些方法可以获得可能出错的提示禁用编辑器插件编辑器体验受插件影响。尝试禁用插件(尤其是JavaScript/TypeScript相关插件),看看是否能解决性能和响应问题。一些编辑器也有自己的性能故障排除指南,因此请考虑阅读该指南。例如,VisualStudioCode对性能问题也有自己的介绍。诊断扩展您可以使用--extendedDiagnostics运行TypeScript以获取编译器花费的时间日志。请注意,总时间不是之前所有时间的总和,因为有一些重叠,有些工作没有测量。对于大多数用户而言,最相关的信息是:鉴于这些输入,您可能想问一些问题:文件数/代码行数是否与项目中的文件数大致一致?如果不是,请尝试运行--listFiles程序时间或I/O读取时间是否相当长?确保您的包含/排除配置正确其他时候有些地方看起来不对?你可能想问一个问题。如果使用emitDeclarationOnly运行时打印时间过长,您可以做一些事情来帮助诊断阅读关于报告编译器性能问题的说明.showConfig可以解释tsc将为调用计算什么。跟踪解析运行traceResolution可以帮助解释编译中包含文件的原因。输出有点繁琐,因此您可能希望将输出重定向到一个文件。如果您发现不应该存在的文件,您可能需要修改tsconfig.json中的包含/排除列表,或者,您可能需要调整其他设置,例如类型、typeRoots或路径。独立运行tsc很多时候,用户在使用Gulp、Rollup、Webpack等第三方构建工具时会遇到性能下降的情况。运行tsc--extendedDiagnostics以查找TypeScript和工具之间的差异,以指示外部配置中的错误或效率低下。需要注意的一些问题:tsc和TypeScript集成的构建工具在构建时间上有很大差异吗?如果构建工具提供诊断,TypeScript的分辨率和构建工具的分辨率之间是否存在差异?构建工具是否有自己的配置,可能是什么原因?构建工具是否可能是配置TypeScript集成的原因?(例如ts-loader的选项?)升级依赖项有时TypeScript的类型检查会受到计算密集型.d.ts文件的影响。这种情况很少见,而且很可能会发生。升级到更新的TypeScript版本(可以更高效)或更新版本的@types包(可能已经恢复了回归)通常可以解决问题。常见问题排除故障后,您可能想要探索一些常见问题的修复方法。如果以下解决方案不起作用,可能值得提出一个问题。包含和排除配置不当如上所述,包含/排除选项可能会以多种方式被滥用提出问题如果您的项目已经正确配置以进行优化,您可能想要提出问题。最佳性能问题报告包含易于访问和最少的问题重现。换句话说,一个代码库很容易通过git克隆,只包含几个文件。它们不需要与构建工具进行外部集成——它们可以通过独立代码调用tsc或调用TypeScriptAPI来完成。需要复杂调用和设置的代码库没有被优先考虑。我们理解这一点,但做到这一点并不容易——特别是,很难在代码库中隔离问题的根源,共享知识产权也可能是一个问题。在某些情况下,如果我们认为问题影响很大,团队将愿意发送保密协议(NDA)。无论是否可以重现,在提交问题时遵循这些方法将有助于为您提供性能修复。报告编译器性能问题有时,您会在构建时间和编辑场景期间发现性能问题。在这种情况下,最好关注TypeScript编译器。首先,你应该使用下一版本的TypeScript来确保你不会遇到已经解决的问题。编译器问题可能包括安装的TypeScript版本(例如:npxtsc-v或yarntsc-v)、TypeScript正在运行的节点版本(例如:node-v)使用extendedDiagnostics运行的输出(tsc--extendedDiagnostics-ptsconfig.json)理想情况下,一个项目应该能够展示遇到的问题。分析编译器的输出日志(isolate-*-*-*.log和*.cpuprofile文件)。通过使用--trace-ic标志和--generateCpuProfile标志来分析编译器,使TypeScript运行Node.jsv10+,这对于团队提供诊断结果很重要:这里./node_modules/typescript/lib/tsc.js可以用于替换您安装的TypeScript编译器版本,而tsconfig.json可以是任何TypeScript配置文件。profile.cpuprofile是您选择的输出文件。这将生成两个文件:--trace-ic将输出到isolate-*-*-*.log文件(例如isolate-00000176DB2DF130-17676-v8.log)--generateCpuProfile将输出到一个文件中。在上面的示例中,它将是一个名为profile.cpuprofile的文件警告:这些文件可能包含有关您的工作区的信息,包括文件路径和源代码。这两个文件都可以作为纯文本阅读,您可以在将它们作为GitHub问题提交之前对其进行修改。(例如,清理可能暴露内部私人信息的文件路径)。但是,如果您对在GitHub上公开发布这些内容有任何疑虑,请告诉我们,可以私下分享详细信息。报告编辑器性能问题编辑性能通常受到很多因素的影响,TypeScript团队唯一可以控制的是JavaScript/TypeScript语言服务的性能,以及该语言服务和某些编辑器(即VisualStudio、VisualStudioCode、VisualStudioforMac和SublimeText)。确保在编辑器中关闭所有第三方插件,以确定是否TypeScript本身有问题。编辑性能问题略有涉及,但同样的想法适用:可以克隆的最小可重现代码库是理想的,尽管在某些情况下团队将能够签署NDA以调查和隔离问题。包括tsc--extendedDiagnostics的输出是很好的上下文,但获取TSServer日志是最有用的。收集TSServer日志要在VisualStudioCode中收集TSServer日志,请打开命令菜单栏,然后??选择转到“首选项”以打开全局设置。打开用户设置到首选项,然后打开本地项目。打开工作区设置并设置选项"typescript.tsserver.log":"verbose"重新启动VSCode以重现问题在VSCode中,运行TypeScript。打开TS服务器日志命令这将打开tsserver.log文件?警告:TSServer日志可能包含有关您的工作区的信息,包括文件路径和源代码。如果您对在GitHub上公开发布有任何疑虑,请告诉我们,您可以私下分享详细信息。结束