在WordPress 6.3中使用“async”和“defer”属性注册脚本

WordPress 6.3引入了对注册脚本的支持异步推迟属性作为增强增强 增强是对WordPress的简单改进,例如添加挂钩、新功能或对现有功能的改进。核心核心 核心是运行WordPress所需的一组软件。核心开发团队构建WordPress。的现有脚本美国石油学会美国石油学会 API或应用程序编程接口是一种软件中介,允许程序相互交互并以有限的、明确定义的方式共享数据。。这解决了长期Trac机票,并添加了为脚本定义加载策略的功能。支持的策略如下:

  • 阻塞(默认情况下,不提供此策略)
  • 延迟(通过提供延迟加载策略)
  • 异步(通过提供异步加载策略)

此增强最初是在2022年12月.

为什么此增强功能有用?

正在添加推迟异步to script标记可以在不“阻止”页面加载其余部分的情况下加载脚本,从而通过改进的最大内容绘制(LCP)性能产生更高性能的站点。这将带来更好的用户体验。十多年来,这一直是web工程中的常见做法,但到目前为止,在使用核心WordPress API注册/排队脚本时,还没有实现这一点的核心方法或手段。

在此增强之前,开发人员不得不求助于不太理想的替代方案,例如直接在输出点过滤标签(使用脚本加载程序标记 滤波器过滤器 过滤器是两种挂钩之一https://codex.wordpress.org/Plugin_API/挂钩。它们为函数修改其他函数的数据提供了一种方法。它们是Actions的对应物。与Actions不同,过滤器是以孤立的方式工作的,不应该有副作用,例如影响全局变量和输出。,或更糟的是清除url过滤器),或处理标签标签 Subversion中的目录。WordPress使用标签来存储版本(3.6、3.6.1等)的单个快照,这是版本控制系统中标签的常见约定。(不要与帖子标签混淆。)直接使用输出wp_print_script_tag(打印脚本标记)wp脚本属性过滤器。尽管这是相当常见的做法(因为这是以前唯一可用的方法),但它被认为是“黑客”,因为它没有考虑依赖关系树或内联脚本,这可能会导致与其他脚本的互操作性问题或错误。

递延(通过推迟脚本属性)和异步(通过异步脚本属性)脚本如下:

  • 延迟的脚本
    标记为延迟执行的脚本-通过推迟脚本属性-仅在DOM树完全加载后执行(但在DOMContentLoaded和窗口加载事件之前)。与异步脚本不同,延迟脚本的执行顺序与在DOM中打印/添加脚本的顺序相同。
  • 异步脚本
    标记为异步执行的脚本-通过异步脚本属性-在浏览器加载后立即执行。异步脚本没有保证的执行顺序,因为脚本B(虽然是在脚本a之后添加到DOM中的)可能首先执行,因为它可能在脚本a之前完成加载。这些脚本可能在DOM完全构造之前或DOMContentLoaded事件之后执行。

变更摘要

在较高层次上,这些变化可以概括如下:

  • WordPress现在通过wp_register_script()wp_enqueue_script()功能。
  • 这些函数具有新的函数签名$英寸英尺重载布尔参数以接受新的$个参数数组参数,以便为指定脚本的加载策略提供一个简单的入口点,同时仍然保持对的完全向后兼容性$英寸英尺实施;这保留了通过新的$个参数参数。请注意,还可以通过以下方式以向后兼容的方式指定策略wp_script_add_data().

WP_脚本类是为了方便准备和输出脚本加载策略所需的业务逻辑。

示例1:为脚本指定加载策略

加载策略可以通过wp_register_script()wp_enqueue_script()通过将策略键值对传递给新的/重载的$个参数参数。 

下面的示例显示了一个带有句柄的新脚本“foo”(foo)注册为延迟脚本:

wp_register_script(“foo”,“/path/to/foo.js”,数组(),'1.0.0', 阵列(“战略”=>“推迟”) );

可以通过wp_enqueue_script()功能。

示例2:指定通过新API在页脚中打印脚本

下一个示例显示了使用新API为页脚打印指定的第二个脚本,同时还提供了异步同时加载策略:

wp_register_script(“bar”,“/path/to/bar.js”,数组(),'1.0.0', 阵列(“in_footer”=>true,“策略”=>“异步”,))

可以通过wp_enqueue_script()功能。

实施细节

此功能通过扩展脚本API的常用和众所周知的方面,提供了指定加载策略的简单方法,从而增强了现有的脚本API。在决定“合格策略”时,它还考虑了脚本的依赖关系树(其依赖关系和/或从属关系),以避免应用对一个脚本有效但对树中其他脚本有害的策略,从而导致意外的执行顺序紊乱。在使用上述章节中概述的替代“黑客”方法时,通过先前添加脚本加载策略属性的方法几乎不可能实现这一点。

脚本加载策略增强的技术实现已经在现有脚本API中进行,特别是在WP_脚本类,并通过对熟悉和常用的wp_register_script()wp_enqueue_script()功能。

关于依赖关系与从属关系的注释
为了避免术语混淆,让我们澄清脚本的依赖项与依赖项之间的区别。脚本的依赖关系是指所述脚本本身所依赖的脚本,即它们必须在所述脚本入队之前入队。脚本的受抚养人另一方面,指的是依赖在所述脚本上,即在其依赖关系数组。

对的更改$英寸英尺的参数wp_register_script()wp_enqueue_script()功能

现有的最显著的变化wp_register_script()wp_enqueue_script()functions是函数签名更改,其中$英寸英尺(以前是一个布尔参数)已被重载,以便也接受一个数组$个参数参数,使用以下任意键:

  • (布尔)in_footer
    • 行为与之前执行高层一样$英寸英尺参数。
  • (字符串)策略
    • 接受正在注册/排队的给定脚本的预期加载策略。实施时可用的可接受字符串值为推迟对于延迟脚本和异步用于异步脚本。
    • 默认为阻塞行为,从而保留现有脚本注册和排队的向后兼容性。

保持向后兼容性

对于以前/现有的使用wp_register_script()wp_enqueue_script()使用的函数$英寸英尺布尔参数,通过将脚本组显式设置为适用于页脚或收割台标题 你网站的标题通常是人们第一次体验到的东西。位于页面顶部的刊头或页眉是网站外观的一部分。它可以影响访问者对您的内容和您/您组织的品牌的看法。它在不同的屏幕尺寸上也可能看起来不同。基于传递给新的/重载的布尔值进行打印$个参数参数。因此,保留了完全的向后兼容性,这是对API的一个无中断增强。

虽然此功能中引入的更改本身被认为是非中断的,但在使用新的 $个参数参数(替换/重载上一个$英寸英尺参数)中插件插件 插件是一个包含一组功能的软件,可以添加到WordPress网站。他们可以为你的WordPress网站扩展功能或添加新功能。WordPress插件是用PHP编程语言编写的,并与WordPres无缝集成。这些可以在WordPress.org插件目录中免费https://wordpress.org/插件/或者可以是第三方基于成本的插件/WordPress支持的主题/代码库<6.3,有一种情况下$英寸英尺核心会误解这个意图。以以下场景为例:

wp_register_script(“foo”,'/path/to/foo.js',数组(),'1.0.0', 数组(“策略”=>“延迟”,“in_footer”=>false,//注意:这是默认值。));

在WordPress>=6.3中,这将被正确评估为通过英尺(_F)数组键值为false(这也是默认值)。

然而,在WordPress版本<6.3中,上述数组的存在被分配给$英寸英尺参数本身将计算为布尔值真实的与开发人员的预期相反。话虽如此,有人可能会理所当然地认为,在不支持延迟/异步脚本的WordPress版本中,将它们打印在页脚是下一个最佳选择。

防止这种互操作性问题的最简单方法是通过不同于$个参数参数到wp_register_script()wp_enqueue_script()功能。

它可以通过wp_script_add_data()在这种情况下,WordPress 6.3会理解它,但旧版本会忽略它。

wp_register_script(“foo”“/path/to/foo.js”数组()'1.0.0', );wp_script_add_data(“foo”、“strategy”、“defer”);

或者,通过将脚本注册/排队包装在一个包装函数中,该包装函数负责新旧函数签名,从而保持完全向后兼容性,可以实现6.3及以上版本WordPress之间的互操作性,每个脚本使用一个函数调用。

这种脚本注册/排队包装器的示例可能如下所示:

myplugin_register_script($handle、$src、$deps、$ver、$args){全局$wp_version;//如果>=6.3,则重复使用包装器函数签名。if(版本比较($wpversion,'6.3','>=')){wp_注册_脚本($句柄,美元src,$deps,美元,$ver,美元,$个参数);}其他{//提取旧版本使用的in_footer值。$in_footer=isset($args['in_footer'])$args['in_footer']:false;wp_注册_脚本($handle中,美元src,$deps,美元,$ver,美元,$英寸英尺);}}

预期装载策略与合格装载策略

应该注意的是,虽然开发人员可以打算对于包含特定加载策略的给定脚本,最终加载策略可能会因脚本依赖项/从属项和内联脚本等因素而不同。 

例如,如果开发人员注册脚本foo公司对于defer策略,其依赖项必须使用defer或blocking策略,其从属项必须使用defer策略才能维护预期的执行顺序。如果所述脚本的依赖项foo公司然后注册一个阻塞策略,脚本foo公司然后它的所有依赖项都会被阻塞。

中新增的逻辑WP_脚本类负责执行一系列逻辑检查,以确保给定脚本句柄的最终策略是基于上述因素的最合适的策略。

句柄永远不会继承比预期“更严格”的策略,即标记为延迟加载的脚本永远不会更改为异步加载,但如果环境因素允许,结果可能恰恰相反。

内联脚本

将加载策略应用于附加了内联脚本的脚本(或依赖关系树中的脚本)时,会有一些细微差别,因为这最终会影响预期/合格策略的最终结果。

注册在before位置的内联脚本的行为基本上保持不变,因为它们将在主/父脚本解析为立即执行、延迟执行或异步执行之前进行固有的解析和/或执行。

在after位置注册的内联脚本(默认为wp_add_inline_script())但是,如果所述主/父脚本具有异步或延迟的合格策略,则会影响主/父script的最终加载策略。这主要是因为在确保附加到延迟/异步脚本的内联脚本在适当和预期的时间执行时很复杂,同时不会对父脚本本身和整个依赖关系树产生负面影响。

因此,如果给定的脚本句柄在after位置包含内联脚本,则该脚本将被假定为阻塞,并且任何预期的策略(如defer/async)都将被删除,最终符合条件的策略为舞台调度。这反过来可能会影响脚本的依赖关系树,其中的所有脚本也可能被视为阻塞脚本,以保持排队脚本的正确执行顺序和功能。逻辑被明确地用于确保在这些实例中脚本树的正确执行顺序。

后续行动 为bug报告和bug跟踪器上的功能开发创建。 #58632已开放以继续进行中的讨论和概念验证实现,从而可能在将来引入延迟的内联after脚本执行,从而保持其加载顺序。

迁移到新API

使用遗留方法添加的代码实现异步推迟脚本标记的属性应迁移到新API。这些场景包括属性历史上通过脚本加载程序标记过滤器,或通过清除url过滤器。

以下示例显示了使用脚本阅读器标签清除url过滤器,这些过滤器现在被认为是不太理想的方法,然后展示如何使用新的API完成这项工作:

迁移迁移 将网站的代码、数据库和媒体文件从一台服务器移动到另一台服务器。通常在更换托管公司时进行。考虑示例1:添加推迟属性,通过脚本加载程序标记滤波器

函数old_approach($tag,$handle){//仅影响foo脚本。if('foo'!==$handle){返回$url;}//现代实现可能在此处使用WP_HTML_Tag_Processor。return str_replace('src=','defer src=`,$tag);}add_filter('script_loader_tag',old_approach,10,2);

迁移注意事项示例2:添加推迟属性,通过清除url滤波器

//警告:这始终是硬的,不建议使用。函数old_brittle_approach($url){//仅影响foo脚本。if(false===strpos($url,'foo.js')){返回$url;}return“$url'defer”;//假设单引号属性!}add_filter('clean_url','old_brittle_approach');

如果您使用与上面类似的方法添加推迟异步属性,请使用本文前面概述的任何一种方法迁移到新API。

道具:@乔麦吉尔 @弗利克索斯90 @威斯顿鲁特 @亚当西尔弗斯坦 @约尔斯纳 @史蒂文林克斯

#6-3,#开发说明,#开发说明6-3