1. 重写ajax和fetch请求的原型方法不会导致请求变慢
第一阶段:接入方的业务系统一直说页面加载慢,肉眼客观的那种慢。我一直以为是因为我重写了ajax和fetch的原型方法导致。 一直以为是我们的监控SDK导致业务系统的请求响应变慢了,所以排查到Ajax和fetch等代码的AOP处的代码。我们为了验证这块代码的影响,拉着业务方一起跑了几十万的数据,最终得出的结论也就是对业务系统会有8ms左右的影响,也到不了这种肉眼客观的慢。
在这个过程中学到了不少知识:
-
浏览器并发的请求数 一般默认的是6个(firfox和chrome都查过默认配置)。为什么会查到这块的知识?因为业务系统同时发送了30多个请求,我们认为是监控导致了这块的排队时间,就查到了这块的知识。所以在这里我们也提出优化建议,不要把这么接口一次性请求,要么分布在不同的域名上,要么优化成6个以内的接口去完成这部分逻辑。
-
ajax的轮询
(1) 使用定时器只做一个定时轮询
一般的做法是在客户端定时发送ajax请求,也就是轮询,如果服务器有新数据返回新数据,否则返回空响应。轮询实现起来简单,但也经常效率很低。其中关键在于选择轮询间隔:长轮询间隔意味着延迟交付,而短轮询间隔会导致客户端与服务器间不必要的流量和协议开销。定时轮询的一个大问题就是很可能造成大量没必要的空检查。
(2) 使用ajax实现长轮询
通过将连接一直保持打开到有更新(长轮询),就可以把更新立即从服务器发送给客户端。这样,长轮询就解决了消息交付延迟的问题,同时也消灭了空检查,减少了XHR请求次数和轮询的整体开销。在交付更新后,长轮询请求完成,然后客户端再发送下一次长轮询请求,等待下一次更新:
function checkUpdates(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = function() { ... checkUpdates('/updates'); }; xhr.send(); } checkUpdates('/updates');(3)Server-Sent Events
Server-Sent Events(SSE)让服务器可以向客户端流式发送文本消息,比如服务器上生成的实时通知或更新。为达到这个目标,SSE设计了两个组件:浏览器中的EventSource和新的“事件流”数据格式。其中,EventSource可以让客户端以DOM事件的形式接收到服务器推送的通知,而新数据格式则用于交付每一次更新。 EventSource API和定义完善的事件流数据格式,使得SSE成为了在浏览器中处理实时数据的高效而不可或缺的工具: · 通过一个长连接低延迟交付; · 高效的浏览器消息解析,不会出现无限缓冲; · 自动跟踪最后看到的消息及自动重新连接; · 消息通知在客户端以DOM事件形式呈现。 实际上,SSE提供的是一个高效、跨浏览器的XHR流实现,消息交付只使用一个长HTTP连接。然而,与我们自己实现XHR流不同,浏览器会帮我们管理连接、解析消息,从而让我们只关注业务逻辑。
(4)websocket
WebSocket可以实现客户端与服务器间双向、基于消息的文本或二进制数据传输。它是浏览器中最靠近套接字的API。但WebSocket连接远远不是一个网络套接字,因为浏览器在这个简单的API之后隐藏了所有的复杂性,而且还提供了更多服务: · 连接协商和同源策略; · 与既有HTTP基础设施的互操作; · 基于消息的通信和高效消息分帧; · 子协议协商及可扩展能力。 WebSocket是浏览器中最通用最灵活的一个传输机制,其极简的API可以让我们在客户端和服务器之间以数据流的形式实现各种应用数据交换(包括JSON及自定义的二进制消息格式),而且两端都可以随时向另一端发送数据。 不过,自定义数据交换协议的问题通常也在于自定义。因为应用必须考虑状态管理、压缩、缓存及其他原来由浏览器提供的服务。设计限制和性能权衡始终会有,利用WebSocket也不例外。简单来说,WebSocket并不能取代HTTP、XHR或SSE,而为了追求最佳性能,关键还是要利用这些机制的长处。
第二阶段:频繁的设置请求头也不会导致也去请求变慢,这里的结论我们是分别单条请求铺了10w+数据和10条请求铺了10w+数据以后,分别取avg, p25, p55, p75, p95以后得出来的结论是setRequestHeader和fetch 设置header都不会对原有请求造成太多性能消耗,大约在8ms左右,这个时间可以忽略不计。
2. 设置事件监听会对业务系统有比较大的影响
为什么在接入监控SDK后会变慢?按我的分析,因为我们在SDK中设置的事件监听导致了请求响应事件的执行顺序。这里用到的知识, Event Loop, 宏任务,微任务,requestIdleCallback等方面的知识。
关于这方面的知识:
一次弄懂Event Loop(彻底解决此类面试问题) requestIdleCallback
针对这个问题,在监听事件的回调中所有的处理逻辑都放进低优先级队列中执行或者保证在事件队列的最后面。保证我们的处理逻辑是最后执行。