单页面应用程序(SPA)可能要花很长时间才能发射。这是一个巨大的问题,因为即使延迟一秒钟也会使您花费7%的转化。
但是就像您可以使单页应用程序对SEO友好一样,您也可以提高其性能。
因此,这是我们的详细指南,针对那些希望在2020年加速SPA应用程序的人。对于那些不熟悉SPA概念的人,我建议从我们的文章开始,内容是什么是单页应用程序以及它们与传统多页应用程序的比较页应用程序。
监控您的SPA效果
有很多工具可以帮助您监视SPA性能。首先,您可以使用Chrome Devtools扩展,例如Lighthouse,Ember Inspector或React Performance Devtools。
此类工具的问题在于它们不能反映出您的SPA的感知加载速度(这对用户来说很重要)。
还有诸如速度索引之类的其他工具集,它们试图匹配实际的用户体验。
但是实际用户来自各种各样的设备/网络,因此很难在综合测试环境中考虑所有这些因素。
我们建议您使用真实用户监视(RUM)。它被动地跟踪人们与您的应用程序的每次交互,从而为您提供有关用户如何感知其加载速度的准确实时图像。
如果您喜欢现成的解决方案,那么这里是一些支持单页应用程序的RUM工具的简短列表:
- Dynatrace
- Catchpoint
- Akamai mPulse (former Soasta)
- Appdynamics
- Raygun Real User Monitoring
- Sematext Experience
- New Relic Browser
您还可以要求您的开发团队将RUM应用于SPA。
它必须识别连续导航的开始(又称软导航/页面内导航:应用启动后,用户单击指向SPA中新“页面”的链接/按钮)以及页面完全被载入的那一刻。已加载。开发人员可以通过几种方式实现此目的:
- 使用Resource Timing API识别何时进行AJAX调用以查明页内导航的开始;
- 使用Mutation Observer可以检测到对DOM的修改,并通过Resource Timing API识别网络活动的结束。
实践表明,这些方法可能不可靠,并且结果不准确。例如,即使用户不启动页内导航,您的SPA也会调用AJAX来预取一些数据。否则结果可能会因网络活动而歪曲,而不会影响屏幕上发生的事情。
为了解决这个问题,他们可以使用简单的API来衡量加载时间:
var rumObj = new RumTracking({
'web-ui-framework': 'EMBER'
});
// App Launch - window.performance.timing.navigationStart is the start marker
rumObj.setPageKey('feed_page_key');
// Do rendering
rumObj.appRenderComplete();
// Successive navigation
rumObj.appTransitionStart();
rumObj.setPageKey('profile_page_key');
// Do rendering
rumObj.appRenderComplete();
使用这种方法,每个页面都必须编写检测代码。
许多单页应用程序JavaScript框架都有生命周期hooks ,可用于自动执行检测。
// Add instrumentation for successive navigation start
router.on('willTransition', () => {
a. rumObj.appTransitionStart();
});
// Add instrumentation for rendering is complete
router.on('didTransition', () => {
Ember.run.scheduleOnce('afterRender', () => {
a. rumObj.appRenderComplete();
});
});
因此,开发人员可以使用Navigation Timing API的导航开始来检测初始导航的开始。路由器的willTransition事件将标志着页面内导航的开始。
通过监听еруdidTransition事件并在afterRender队列中添加工作,您将知道两种模式下页面的完全加载时间。
现在,您已经拥有测量加载时间所需的一切。要发现性能瓶颈,您需要细分RUM数据。您可以通过User Timing API检测单个资源的加载时间。
典型的SPA的性能瀑布外观现在是时候分析RUM数据,看看可以如何解决瓶颈了。
改善SPA性能的六大方法
1.懒惰地呈现折叠式内容
简而言之,这意味着仅呈现页面上当前对用户可见的那些部分(即首屏内容)。
如果您的SPA在渲染阶段花费大量时间(请参见上图),则惰性渲染很有用。在此阶段,应用程序将为页面上的所有组件创建DOM(有关如何在页面上表示文本,图像和其他对象的规范)。
一旦为首个组件构建了DOM,就可以产生浏览器的主线程。这将加快SPA的启动速度,因为您不必呈现当前不需要的资源。
将渲染优先级分配给页面上的所有组件可能会带来另一个性能提升(因此浏览器不会同时渲染所有组件)。
这样,您可以加快“第一个有意义的画图”(即用户看到页面核心内容的时间)。通过不渲染某些不可见的组件,您还将改善“互动时间”。
2.使用延迟数据获取
加快渲染阶段之后,您可能需要研究过渡阶段。
此时,SPA加载数据,对其进行规范化并将其推送到存储中。为了减少在此阶段花费的时间,您需要减少SPA处理的数据量。
正如您可以懒惰地呈现折叠式内容一样,您可以推迟加载数据,直到真正需要它为止。
您可以使用一个高级调用来获取“第一有意义绘画”所需的数据,而可以使用另一个调用来懒惰地加载页面所需的其余数据。
注意:上述方法适用于启动模式和页内导航,因为它们减少了前端时间。
一些SPA框架(例如React,Angular或Vue)允许开发人员将应用程序代码分成几个捆绑包。您可以同时或在必要时加载它们。第二个选项可以加快第一个导航的速度。例如,您可以仅加载用户可以立即访问的部件,而推迟其他所有操作(例如,需要授权的部件)。
3.缓存静态内容
研究您的SPA,以确定何时可以在用户设备上存储图像和其他静态资源。
即使使用最佳服务器,从内存或Web存储中提取数据所需的时间也比发送HTTP请求少得多。
设备内存比最快的网络快得多。因此,缓存是您最好的朋友。
对于大量集合,您可以使用某种分页并依靠服务器来保持持久性,或者编写LRU算法来从存储中擦除备用项。
您可以使用Service Worker在SPA中缓存静态内容。
它们是在后台运行的客户端脚本。您可以使用它们来减少流量并启用脱机功能。当浏览器请求内容时,它首先经过服务人员。如果请求的内容存在于缓存中,则服务工作者将检索它并显示在屏幕上。在其他情况下,它将从网络请求资源。
您还可以使用IndexedDB API缓存大量结构化数据。
4.在适当的地方使用WebSockets(即用于高度交互的应用程序)
WebSocket是允许用户浏览器和服务器之间进行双向通信的协议。与HTTP不同,客户端不必不断向服务器发送请求以获取新消息。取而代之的是,浏览器仅侦听服务器并在就绪时接收消息。
结果,您得到的连接在某些情况下可以比常规HTTP快400%。
您可以使用socket.io之类的服务为SPA实现WebSockets。
5.使用JSONP / CORS绕过同源策略
许多应用程序的某些功能都依赖于第三方API。
但是由于同源策略,您无法对浏览器认为位于另一台服务器上的页面进行AJAX调用。要获得对第三方API的访问权限,该应用将必须使用源服务器作为代理。
额外的往返意味着更多的延迟。
如果不处理检索到的数据并且不将其存储在系统中,则可以直接请求资源。为此,您可以使用带有填充的JSON(JSONP)或跨域资源共享(CORS)
JSON with Padding
JSONP充分利用了浏览器允许您添加来自其他域的<script>标签的事实。通过JSONP请求,您可以动态构造这些标签,并将URL参数传递给必要的资源。
然后,标记会在JSON响应中返回资源。
但是有一个缺点。使用<script>标记时,JSONP仅适用于<GET>请求。您可以通过将async和defer属性添加到外部脚本来进一步提高性能。如果没有这些属性,浏览器必须先下载并执行脚本,然后才能显示页面的其余部分。
这减慢了感知的加载速度。
如果包含async属性,则浏览器在加载脚本时不会停止解析页面,但是在执行脚本时仍会暂停解析。该延迟属性,另一方面,直到页面完全解析延迟脚本执行
跨域资源共享
CORS允许您定义可以访问服务器内容的人员和方式。
但是有一个问题。使用除GET,HEAD和POST之外的任何方法的请求将启动预检检查,以确认服务器已准备好进行跨域请求。
为了运行检查,客户端发送另一个请求,该请求描述了跨域AJAX调用的来源,方法和标头。根据此信息,服务器决定是否处理该呼叫。客户端收到响应后,将启动对第三方资源的请求。
preflight检查增加了第二次往返,因此可以有效地将您的延迟加倍。
preflight checks
您可以使用以下方法之一来处理预检请求:
1.编写API并仅使用HEAD,GET,POST,Accept,Accept-Language,Content-Language和Content-Type来提供内容,因为它们不会启动预检请求。
在接受头使您能够定义可接受的内容类型的能力。默认情况下,首选类型为text / html,但是您可以将application / json或任何其他类型的内容作为唯一的可接受类型。然后,您的后端将检查Accept标头,然后选择发送HTML,JSON或其他响应。
2.缓存预检响应以减少后续检查。
在这种情况下,您不能依靠通常的Cache-Control标头来定义缓存策略。但是您可以改用新的Access-Control-Max-Age标头。其数值定义了缓存响应所需的秒数。
6.使用内容传送网络(CDN)
CDN是遍布全球的服务器网络。您可以使用CDN以更有效的方式传递静态资源(如图像)。网络中的每个服务器都包含原始服务器上托管的内容的缓存版本。
如果来自墨尔本的用户请求图像,则网络将不会从位于纽约的原始服务器获取图像。CDN将使用澳大利亚服务器(或等待时间最少的备用服务器)来提供缓存的内容。
对单页应用程序使用CDN意味着更快地加载脚本并减少了交互时间。增加安全性是一个不错的奖励。
结论说明
这些是我们加快单页应用程序速度的6种方法。
这是一个奖励:测量,优化,重复(但仅在需要时)。
此建议适用于任何应用程序,因为优化是一个连续的过程。
您对代码所做的每次更改都会影响页面加载速度。因此,请评估您的SPA的行为,并避免过早的优化,因为开发人员会花费大量时间来调整其应用程序中不必要的部分。
网友评论