如何在控制台分别打印AJAX API调用各阶段耗时日志?
记录AJAX API调用各阶段耗时的实现方法
方法一:使用PerformanceObserver监听性能条目
这是最可靠的方式,能直接获取浏览器原生记录的所有请求阶段耗时,同时支持XMLHttpRequest和fetch请求。
const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { // 仅过滤AJAX或fetch类型的请求 if (['xmlhttprequest', 'fetch'].includes(entry.initiatorType)) { console.log(`[${entry.name}] Started: ${entry.fetchStart.toFixed(2)}ms (相对页面加载起始时间)`); console.log(`[${entry.name}] Queueing: ${(entry.requestStart - entry.fetchStart).toFixed(2)}ms`); console.log(`[${entry.name}] Stalled: ${(entry.domainLookupStart - entry.fetchStart).toFixed(2)}ms`); console.log(`[${entry.name}] Request sent: ${(entry.requestStart - entry.domainLookupEnd).toFixed(2)}ms`); console.log(`[${entry.name}] Waiting for server response: ${(entry.responseStart - entry.requestStart).toFixed(2)}ms`); console.log(`[${entry.name}] Content Download: ${(entry.responseEnd - entry.responseStart).toFixed(2)}ms`); } } }); // 启动监听资源性能条目 observer.observe({ entryTypes: ['resource'] });
方法二:重写XMLHttpRequest原型(仅支持传统AJAX)
通过拦截原生XMLHttpRequest的方法,结合Performance API获取各阶段耗时:
// 保存原生方法 const originalOpen = XMLHttpRequest.prototype.open; const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._requestUrl = url; originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(body) { // 监听请求完成状态 this.addEventListener('readystatechange', () => { if (this.readyState === XMLHttpRequest.DONE) { // 请求完成后获取对应性能条目 const entry = performance.getEntriesByName(this._requestUrl)[0]; if (entry) { console.log(`[${this._requestUrl}] Started: ${entry.fetchStart.toFixed(2)}ms`); console.log(`[${this._requestUrl}] Queueing: ${(entry.requestStart - entry.fetchStart).toFixed(2)}ms`); console.log(`[${this._requestUrl}] Stalled: ${(entry.domainLookupStart - entry.fetchStart).toFixed(2)}ms`); console.log(`[${this._requestUrl}] Request sent: ${(entry.requestStart - entry.domainLookupEnd).toFixed(2)}ms`); console.log(`[${this._requestUrl}] Waiting for server response: ${(entry.responseStart - entry.requestStart).toFixed(2)}ms`); console.log(`[${this._requestUrl}] Content Download: ${(entry.responseEnd - entry.responseStart).toFixed(2)}ms`); } } }); originalSend.apply(this, arguments); };
方法三:重写fetch方法(支持现代fetch请求)
针对fetch API,结合Performance API实现阶段耗时记录:
const originalFetch = window.fetch; window.fetch = async function(resource, options) { const response = await originalFetch(resource, options); // 克隆响应并读取内容,确保性能条目已完整生成 await response.clone().text(); const entry = performance.getEntriesByName(resource.toString())[0]; if (entry) { console.log(`[${resource}] Started: ${entry.fetchStart.toFixed(2)}ms`); console.log(`[${resource}] Queueing: ${(entry.requestStart - entry.fetchStart).toFixed(2)}ms`); console.log(`[${resource}] Stalled: ${(entry.domainLookupStart - entry.fetchStart).toFixed(2)}ms`); console.log(`[${resource}] Request sent: ${(entry.requestStart - entry.domainLookupEnd).toFixed(2)}ms`); console.log(`[${resource}] Waiting for server response: ${(entry.responseStart - entry.requestStart).toFixed(2)}ms`); console.log(`[${resource}] Content Download: ${(entry.responseEnd - entry.responseStart).toFixed(2)}ms`); } return response; };
关键逻辑说明
各阶段耗时对应PerformanceResourceTiming字段的计算规则:
- Queueing:请求进入队列到开始处理的时间 →
requestStart - fetchStart - Stalled:请求被阻塞的时间 →
domainLookupStart - fetchStart - Request sent:发送请求的时间 →
requestStart - domainLookupEnd(DNS解析完成到请求发送的时长) - Waiting for server response:等待服务器响应的时间 →
responseStart - requestStart(请求发送到收到第一个字节的时长) - Content Download:下载响应内容的时间 →
responseEnd - responseStart(收到第一个字节到响应完全接收的时长)
现代浏览器均支持Performance API,IE11仅支持有限的性能条目字段。
内容的提问来源于stack exchange,提问作者arjunsingh
相关产品推荐
相关产品推荐

