前端異常監(jiān)控之如何捕獲并上報(bào)JS錯(cuò)誤與白屏詳解
引言
在現(xiàn)代前端開發(fā)中,用戶體驗(yàn)是衡量產(chǎn)品成功與否的關(guān)鍵指標(biāo)。然而,前端應(yīng)用運(yùn)行在復(fù)雜多變的環(huán)境中,瀏覽器差異、網(wǎng)絡(luò)問題、設(shè)備性能等因素都可能導(dǎo)致各種異常情況的發(fā)生。如何及時(shí)發(fā)現(xiàn)并解決這些問題,成為前端工程師面臨的重要挑戰(zhàn)。
本文將深入探討前端異常監(jiān)控的核心技術(shù),包括JS錯(cuò)誤捕獲、白屏監(jiān)控以及錯(cuò)誤上報(bào)機(jī)制,幫助開發(fā)者構(gòu)建更加穩(wěn)定可靠的前端應(yīng)用。
一、JS錯(cuò)誤捕獲技術(shù)
1.1 try-catch 語句
最基礎(chǔ)的錯(cuò)誤捕獲方式是使用 try-catch 語句,它可以捕獲代碼塊中同步執(zhí)行的錯(cuò)誤:
/**
* 捕獲同步代碼錯(cuò)誤
* @param {Function} fn - 要執(zhí)行的函數(shù)
* @param {Function} fallback - 錯(cuò)誤處理函數(shù)
* @returns {any} 函數(shù)執(zhí)行結(jié)果
*/
function safeExecute(fn, fallback) {
try {
return fn();
} catch (error) {
console.error('執(zhí)行出錯(cuò):', error);
return fallback ? fallback(error) : null;
}
}
// 使用示例
safeExecute(
() => {
const result = 10 / 0; // 會(huì)導(dǎo)致錯(cuò)誤
return result;
},
(error) => {
console.log('捕獲到錯(cuò)誤,執(zhí)行備用方案');
return 0;
}
);
局限性:try-catch 只能捕獲同步錯(cuò)誤,無法捕獲異步錯(cuò)誤和Promise中的錯(cuò)誤。
1.2 window.onerror 事件
window.onerror 可以捕獲全局范圍內(nèi)的JS錯(cuò)誤,包括異步錯(cuò)誤:
/**
* 全局錯(cuò)誤捕獲
*/
function setupGlobalErrorHandler() {
window.onerror = function(message, source, lineno, colno, error) {
console.error('全局錯(cuò)誤:', {
message,
source,
lineno,
colno,
error
});
// 這里可以添加錯(cuò)誤上報(bào)邏輯
return true; // 阻止默認(rèn)處理
};
}
// 啟用全局錯(cuò)誤捕獲
setupGlobalErrorHandler();
注意事項(xiàng):
- 對于跨域腳本,需要在腳本標(biāo)簽中添加
crossorigin屬性 - 某些瀏覽器可能不會(huì)提供完整的錯(cuò)誤信息
1.3 Promise 錯(cuò)誤捕獲
Promise 中的錯(cuò)誤需要使用 catch 方法或 unhandledrejection 事件來捕獲:
/**
* Promise 錯(cuò)誤捕獲
*/
function setupPromiseErrorHandler() {
window.addEventListener('unhandledrejection', function(event) {
console.error('未處理的Promise錯(cuò)誤:', {
reason: event.reason,
promise: event.promise
});
// 這里可以添加錯(cuò)誤上報(bào)邏輯
event.preventDefault(); // 阻止默認(rèn)處理
});
}
// 啟用Promise錯(cuò)誤捕獲
setupPromiseErrorHandler();
1.4 Vue 應(yīng)用中的錯(cuò)誤捕獲
在 Vue 應(yīng)用中,可以使用 errorHandler 來捕獲組件渲染和觀察期間的錯(cuò)誤:
import Vue from 'vue';
/**
* Vue 錯(cuò)誤捕獲
*/
Vue.config.errorHandler = function(err, vm, info) {
console.error('Vue 錯(cuò)誤:', {
error: err,
component: vm ? vm.$options.name || 'Anonymous Component' : 'Unknown',
info // 錯(cuò)誤發(fā)生的位置信息
});
// 這里可以添加錯(cuò)誤上報(bào)邏輯
};
對于 Vue 3,可以使用 app.config.errorHandler:
import { createApp } from 'vue';
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
console.error('Vue 3 錯(cuò)誤:', {
error: err,
instance,
info
});
// 這里可以添加錯(cuò)誤上報(bào)邏輯
};
app.mount('#app');
二、白屏監(jiān)控技術(shù)
白屏是前端應(yīng)用中另一個(gè)嚴(yán)重影響用戶體驗(yàn)的問題。白屏監(jiān)控主要有以下幾種方案:
2.1 基于DOM元素的監(jiān)控
通過檢查關(guān)鍵DOM元素是否存在來判斷是否發(fā)生白屏:
/**
* 白屏監(jiān)控 - 基于DOM元素
* @param {string} selector - 關(guān)鍵DOM元素選擇器
* @param {number} timeout - 超時(shí)時(shí)間(ms)
* @param {Function} callback - 白屏回調(diào)
*/
function monitorWhiteScreen(selector, timeout = 3000, callback) {
const checkTime = Date.now();
function checkElement() {
const element = document.querySelector(selector);
if (element) {
console.log('頁面正常加載');
} else {
if (Date.now() - checkTime > timeout) {
console.error('檢測到白屏');
if (callback) {
callback();
}
} else {
requestAnimationFrame(checkElement);
}
}
}
requestAnimationFrame(checkElement);
}
// 使用示例
monitorWhiteScreen('#app', 5000, () => {
// 白屏處理邏輯
console.log('上報(bào)白屏事件');
});
2.2 基于視覺的監(jiān)控
通過檢查頁面的可見內(nèi)容來判斷是否發(fā)生白屏:
/**
* 白屏監(jiān)控 - 基于視覺
* @param {number} threshold - 閾值(0-1)
* @param {number} timeout - 超時(shí)時(shí)間(ms)
* @param {Function} callback - 白屏回調(diào)
*/
function monitorVisualWhiteScreen(threshold = 0.8, timeout = 3000, callback) {
const checkTime = Date.now();
function checkVisual() {
if (Date.now() - checkTime > timeout) {
const body = document.body;
const rect = body.getBoundingClientRect();
const area = rect.width * rect.height;
if (area === 0) {
console.error('檢測到白屏:body面積為0');
if (callback) callback();
return;
}
// 這里可以添加更復(fù)雜的視覺檢測邏輯
// 例如使用Canvas截圖分析像素
console.log('頁面視覺檢查通過');
} else {
requestAnimationFrame(checkVisual);
}
}
requestAnimationFrame(checkVisual);
}
2.3 基于性能指標(biāo)的監(jiān)控
利用Performance API監(jiān)控頁面加載性能,間接判斷白屏情況:
/**
* 白屏監(jiān)控 - 基于性能指標(biāo)
* @param {number} timeout - 超時(shí)時(shí)間(ms)
* @param {Function} callback - 白屏回調(diào)
*/
function monitorPerformanceWhiteScreen(timeout = 5000, callback) {
const checkTime = Date.now();
function checkPerformance() {
if (Date.now() - checkTime > timeout) {
const navigation = performance.getEntriesByType('navigation')[0];
if (navigation) {
console.log('頁面性能指標(biāo):', {
domContentLoadedEventEnd: navigation.domContentLoadedEventEnd,
loadEventEnd: navigation.loadEventEnd
});
// 如果關(guān)鍵時(shí)間點(diǎn)為0,可能發(fā)生了白屏
if (navigation.domContentLoadedEventEnd === 0) {
console.error('檢測到白屏:DOM未加載完成');
if (callback) callback();
}
}
} else {
requestAnimationFrame(checkPerformance);
}
}
requestAnimationFrame(checkPerformance);
}
三、錯(cuò)誤上報(bào)機(jī)制
捕獲錯(cuò)誤只是第一步,更重要的是將錯(cuò)誤信息上報(bào)到服務(wù)器,以便開發(fā)團(tuán)隊(duì)及時(shí)發(fā)現(xiàn)和解決問題。
3.1 錯(cuò)誤上報(bào)數(shù)據(jù)結(jié)構(gòu)
一個(gè)完整的錯(cuò)誤上報(bào)數(shù)據(jù)結(jié)構(gòu)應(yīng)該包含以下信息:
/**
* 構(gòu)建錯(cuò)誤上報(bào)數(shù)據(jù)
* @param {Error} error - 錯(cuò)誤對象
* @param {string} type - 錯(cuò)誤類型
* @returns {Object} 錯(cuò)誤上報(bào)數(shù)據(jù)
*/
function buildErrorReport(error, type = 'js') {
return {
// 錯(cuò)誤基本信息
type,
message: error.message || '未知錯(cuò)誤',
stack: error.stack || '',
// 上下文信息
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
// 設(shè)備信息
device: {
screenWidth: window.screen.width,
screenHeight: window.screen.height,
language: navigator.language
},
// 網(wǎng)絡(luò)信息
network: navigator.connection ? {
type: navigator.connection.type,
effectiveType: navigator.connection.effectiveType,
rtt: navigator.connection.rtt
} : null,
// 用戶信息(可選,需注意隱私)
userId: getUserId() // 假設(shè)有一個(gè)獲取用戶ID的函數(shù)
};
}
3.2 錯(cuò)誤上報(bào)策略
為了平衡實(shí)時(shí)性和性能,需要設(shè)計(jì)合理的錯(cuò)誤上報(bào)策略:
/**
* 錯(cuò)誤上報(bào)管理器
*/
class ErrorReporter {
constructor() {
this.queue = [];
this.batchSize = 10; // 批量上報(bào)大小
this.debounceTime = 1000; // 防抖時(shí)間(ms)
this.debounceTimer = null;
this.apiUrl = '/api/error-report'; // 上報(bào)接口
}
/**
* 上報(bào)錯(cuò)誤
* @param {Object} errorData - 錯(cuò)誤數(shù)據(jù)
*/
report(errorData) {
this.queue.push(errorData);
this.scheduleReport();
}
/**
* 調(diào)度上報(bào)
*/
scheduleReport() {
if (this.queue.length >= this.batchSize) {
this.flush();
return;
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(() => {
this.flush();
}, this.debounceTime);
}
/**
* 執(zhí)行上報(bào)
*/
async flush() {
if (this.queue.length === 0) return;
const errors = [...this.queue];
this.queue = [];
try {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ errors })
});
if (!response.ok) {
console.error('錯(cuò)誤上報(bào)失敗:', response.status);
// 失敗后可以重試或存儲到本地
this.queue.unshift(...errors);
} else {
console.log('錯(cuò)誤上報(bào)成功');
}
} catch (error) {
console.error('上報(bào)網(wǎng)絡(luò)錯(cuò)誤:', error);
// 網(wǎng)絡(luò)錯(cuò)誤時(shí)存儲到本地
this.queue.unshift(...errors);
}
}
}
// 創(chuàng)建錯(cuò)誤上報(bào)實(shí)例
const errorReporter = new ErrorReporter();
3.3 本地存儲與重試機(jī)制
為了應(yīng)對網(wǎng)絡(luò)不穩(wěn)定的情況,可以添加本地存儲和重試機(jī)制:
/**
* 增強(qiáng)版錯(cuò)誤上報(bào)管理器
*/
class EnhancedErrorReporter extends ErrorReporter {
constructor() {
super();
this.storageKey = 'error-reports';
this.loadFromStorage();
}
/**
* 從本地存儲加載錯(cuò)誤
*/
loadFromStorage() {
try {
const stored = localStorage.getItem(this.storageKey);
if (stored) {
const errors = JSON.parse(stored);
this.queue.push(...errors);
localStorage.removeItem(this.storageKey);
console.log('從本地存儲恢復(fù)錯(cuò)誤報(bào)告:', errors.length);
}
} catch (error) {
console.error('加載本地錯(cuò)誤報(bào)告失敗:', error);
}
}
/**
* 保存錯(cuò)誤到本地存儲
*/
saveToStorage() {
try {
if (this.queue.length > 0) {
localStorage.setItem(this.storageKey, JSON.stringify(this.queue));
console.log('錯(cuò)誤報(bào)告已保存到本地存儲');
}
} catch (error) {
console.error('保存錯(cuò)誤報(bào)告到本地存儲失敗:', error);
}
}
/**
* 執(zhí)行上報(bào)
*/
async flush() {
if (this.queue.length === 0) return;
const errors = [...this.queue];
try {
// 調(diào)用父類的flush方法
await super.flush();
} finally {
// 如果還有未上報(bào)的錯(cuò)誤,保存到本地
if (this.queue.length > 0) {
this.saveToStorage();
}
}
}
}
四、綜合監(jiān)控方案
將上述技術(shù)整合起來,構(gòu)建一個(gè)完整的前端異常監(jiān)控系統(tǒng):
4.1 監(jiān)控系統(tǒng)架構(gòu)
/**
* 前端監(jiān)控系統(tǒng)
*/
class FrontendMonitor {
constructor(options = {}) {
this.options = {
errorReportUrl: '/api/error-report',
whiteScreenSelector: '#app',
whiteScreenTimeout: 5000,
...options
};
this.errorReporter = new EnhancedErrorReporter();
this.errorReporter.apiUrl = this.options.errorReportUrl;
this.setupErrorHandlers();
this.setupWhiteScreenMonitor();
}
/**
* 設(shè)置錯(cuò)誤處理器
*/
setupErrorHandlers() {
// 全局錯(cuò)誤處理
window.onerror = (message, source, lineno, colno, error) => {
const errorData = buildErrorReport(error || new Error(message), 'js');
errorData.detail = {
source,
lineno,
colno
};
this.errorReporter.report(errorData);
return true;
};
// Promise錯(cuò)誤處理
window.addEventListener('unhandledrejection', (event) => {
const errorData = buildErrorReport(event.reason, 'promise');
this.errorReporter.report(errorData);
event.preventDefault();
});
// 資源加載錯(cuò)誤
window.addEventListener('error', (event) => {
if (event.target instanceof Element) {
const errorData = {
type: 'resource',
message: `資源加載失敗: ${event.target.src || event.target.href}`,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
detail: {
tagName: event.target.tagName,
src: event.target.src,
href: event.target.href
}
};
this.errorReporter.report(errorData);
}
}, true);
}
/**
* 設(shè)置白屏監(jiān)控
*/
setupWhiteScreenMonitor() {
monitorWhiteScreen(
this.options.whiteScreenSelector,
this.options.whiteScreenTimeout,
() => {
const errorData = {
type: 'white-screen',
message: '頁面白屏',
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
detail: {
selector: this.options.whiteScreenSelector,
timeout: this.options.whiteScreenTimeout
}
};
this.errorReporter.report(errorData);
}
);
}
/**
* 手動(dòng)上報(bào)錯(cuò)誤
* @param {Error|string} error - 錯(cuò)誤對象或錯(cuò)誤信息
* @param {Object} context - 上下文信息
*/
reportError(error, context = {}) {
const errorObj = typeof error === 'string' ? new Error(error) : error;
const errorData = buildErrorReport(errorObj, 'custom');
errorData.context = context;
this.errorReporter.report(errorData);
}
/**
* 上報(bào)性能指標(biāo)
* @param {Object} metrics - 性能指標(biāo)
*/
reportPerformance(metrics) {
const performanceData = {
type: 'performance',
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
metrics
};
this.errorReporter.report(performanceData);
}
}
4.2 使用示例
// 初始化監(jiān)控系統(tǒng)
const monitor = new FrontendMonitor({
errorReportUrl: 'https://monitor.example.com/api/report',
whiteScreenSelector: '.main-content',
whiteScreenTimeout: 8000
});
// 手動(dòng)上報(bào)錯(cuò)誤
function riskyOperation() {
try {
// 可能出錯(cuò)的操作
} catch (error) {
monitor.reportError(error, {
operation: 'riskyOperation',
params: { /* 相關(guān)參數(shù) */ }
});
}
}
// 上報(bào)性能指標(biāo)
function reportPagePerformance() {
const navigation = performance.getEntriesByType('navigation')[0];
if (navigation) {
monitor.reportPerformance({
domContentLoaded: navigation.domContentLoadedEventEnd - navigation.startTime,
loadTime: navigation.loadEventEnd - navigation.startTime,
firstPaint: performance.getEntriesByName('first-paint')[0]?.startTime || 0,
firstContentfulPaint: performance.getEntriesByName('first-contentful-paint')[0]?.startTime || 0
});
}
}
// 頁面加載完成后上報(bào)性能
window.addEventListener('load', reportPagePerformance);
五、實(shí)踐建議與最佳實(shí)踐
5.1 錯(cuò)誤監(jiān)控最佳實(shí)踐
- 分級監(jiān)控:根據(jù)錯(cuò)誤的嚴(yán)重程度進(jìn)行分級,優(yōu)先處理影響用戶體驗(yàn)的嚴(yán)重錯(cuò)誤
- 上下文豐富:上報(bào)錯(cuò)誤時(shí)附帶足夠的上下文信息,如用戶操作路徑、設(shè)備信息等
- 采樣率控制:對于高頻錯(cuò)誤,設(shè)置合理的采樣率,避免上報(bào)數(shù)據(jù)過多
- 版本管理:在錯(cuò)誤上報(bào)中包含應(yīng)用版本信息,便于定位問題
- 測試環(huán)境:在測試環(huán)境中驗(yàn)證監(jiān)控系統(tǒng)的有效性
5.2 白屏監(jiān)控最佳實(shí)踐
- 多維度監(jiān)控:結(jié)合DOM元素檢查、視覺檢查和性能指標(biāo)進(jìn)行綜合判斷
- 閾值調(diào)優(yōu):根據(jù)不同頁面的加載特性,調(diào)整合理的白屏檢測閾值
- 排除干擾:對于首屏確實(shí)為空的頁面,需要設(shè)置排除規(guī)則
- 用戶反饋:提供用戶主動(dòng)反饋白屏的渠道
5.3 性能優(yōu)化建議
- 代碼分割:減少首屏加載時(shí)間,降低白屏概率
- 資源預(yù)加載:對于關(guān)鍵資源,使用預(yù)加載技術(shù)
- 錯(cuò)誤邊界:在React/Vue等框架中使用錯(cuò)誤邊界,防止單個(gè)組件錯(cuò)誤導(dǎo)致整個(gè)應(yīng)用崩潰
- 離線緩存:使用Service Worker緩存靜態(tài)資源,提高頁面加載可靠性
六、實(shí)際應(yīng)用案例
6.1 案例一:電商網(wǎng)站異常監(jiān)控
背景:某電商網(wǎng)站在大促期間頻繁出現(xiàn)白屏和JS錯(cuò)誤,嚴(yán)重影響用戶購物體驗(yàn)。
解決方案:
- 部署前端監(jiān)控系統(tǒng),實(shí)時(shí)捕獲錯(cuò)誤和白屏事件
- 針對高頻錯(cuò)誤進(jìn)行優(yōu)先級排序,快速修復(fù)
- 優(yōu)化首屏加載邏輯,減少白屏?xí)r間
- 建立錯(cuò)誤預(yù)警機(jī)制,當(dāng)錯(cuò)誤率超過閾值時(shí)及時(shí)告警
效果:
- 錯(cuò)誤捕獲率提升至98%以上
- 白屏率從5%下降至0.5%
- 問題定位時(shí)間從小時(shí)級縮短至分鐘級
6.2 案例二:單頁應(yīng)用性能監(jiān)控
背景:某單頁應(yīng)用在復(fù)雜操作時(shí)經(jīng)常出現(xiàn)卡頓和錯(cuò)誤,用戶滿意度低。
解決方案:
- 集成前端監(jiān)控系統(tǒng),捕獲運(yùn)行時(shí)錯(cuò)誤
- 監(jiān)控關(guān)鍵操作的性能指標(biāo),如頁面切換時(shí)間、API響應(yīng)時(shí)間
- 分析錯(cuò)誤分布,發(fā)現(xiàn)并修復(fù)內(nèi)存泄漏問題
- 優(yōu)化路由懶加載策略,減少初始加載時(shí)間
效果:
- 用戶操作錯(cuò)誤率下降60%
- 頁面切換速度提升40%
- 用戶滿意度提升25%
七、未來發(fā)展趨勢
7.1 智能化監(jiān)控
隨著AI技術(shù)的發(fā)展,前端監(jiān)控系統(tǒng)將向智能化方向演進(jìn):
- 錯(cuò)誤聚類:自動(dòng)對錯(cuò)誤進(jìn)行聚類分析,識別相似錯(cuò)誤模式
- 根因分析:利用機(jī)器學(xué)習(xí)算法自動(dòng)分析錯(cuò)誤根因
- 預(yù)測性監(jiān)控:基于歷史數(shù)據(jù)預(yù)測可能出現(xiàn)的問題
- 自適應(yīng)閾值:根據(jù)應(yīng)用狀態(tài)自動(dòng)調(diào)整監(jiān)控閾值
7.2 全鏈路監(jiān)控
前端監(jiān)控將與后端監(jiān)控、用戶行為分析等系統(tǒng)深度融合,構(gòu)建全鏈路監(jiān)控體系:
- 用戶旅程追蹤:從用戶點(diǎn)擊到頁面渲染的完整鏈路監(jiān)控
- 端到端性能監(jiān)控:前端性能與后端API性能的關(guān)聯(lián)分析
- 跨設(shè)備監(jiān)控:統(tǒng)一監(jiān)控不同設(shè)備、不同瀏覽器的表現(xiàn)
- 實(shí)時(shí)可視化:提供直觀的監(jiān)控?cái)?shù)據(jù)可視化界面
7.3 隱私保護(hù)
在監(jiān)控系統(tǒng)發(fā)展的同時(shí),用戶隱私保護(hù)也將成為重要考量:
- 數(shù)據(jù)脫敏:對敏感信息進(jìn)行自動(dòng)脫敏處理
- 合規(guī)性:符合GDPR、CCPA等隱私法規(guī)要求
- 用戶可控:提供用戶選擇退出監(jiān)控的機(jī)制
- 數(shù)據(jù)最小化:只收集必要的監(jiān)控?cái)?shù)據(jù)
八、總結(jié)
前端異常監(jiān)控是構(gòu)建穩(wěn)定可靠前端應(yīng)用的重要保障,它不僅可以幫助開發(fā)者及時(shí)發(fā)現(xiàn)和解決問題,還可以為產(chǎn)品優(yōu)化提供數(shù)據(jù)支撐。本文介紹的JS錯(cuò)誤捕獲、白屏監(jiān)控和錯(cuò)誤上報(bào)技術(shù),為構(gòu)建完整的前端監(jiān)控系統(tǒng)提供了技術(shù)基礎(chǔ)。
在實(shí)際應(yīng)用中,需要根據(jù)項(xiàng)目的具體情況,選擇合適的監(jiān)控策略和技術(shù)方案。同時(shí),要注重監(jiān)控系統(tǒng)本身的性能和可靠性,避免監(jiān)控代碼成為新的性能瓶頸。
隨著前端技術(shù)的不斷發(fā)展,前端監(jiān)控系統(tǒng)也在不斷演進(jìn)。未來,智能化、全鏈路和隱私保護(hù)將成為前端監(jiān)控的重要發(fā)展方向。作為前端開發(fā)者,我們需要持續(xù)關(guān)注這些變化,不斷優(yōu)化監(jiān)控策略,為用戶提供更加穩(wěn)定、流暢的前端體驗(yàn)。
結(jié)語
前端異常監(jiān)控是一項(xiàng)需要持續(xù)投入和優(yōu)化的工作,它不僅是技術(shù)問題,更是產(chǎn)品質(zhì)量和用戶體驗(yàn)的重要組成部分。通過本文介紹的技術(shù)和實(shí)踐,希望能夠幫助開發(fā)者構(gòu)建更加完善的前端監(jiān)控系統(tǒng),讓前端應(yīng)用更加穩(wěn)定可靠,為用戶創(chuàng)造更好的使用體驗(yàn)。
記住,一個(gè)好的監(jiān)控系統(tǒng)不僅能夠捕獲錯(cuò)誤,更能夠幫助我們理解用戶的真實(shí)使用場景,為產(chǎn)品的持續(xù)優(yōu)化提供數(shù)據(jù)驅(qū)動(dòng)的決策依據(jù)。讓我們一起努力,構(gòu)建更加健康的前端生態(tài)系統(tǒng)。
到此這篇關(guān)于前端異常監(jiān)控之如何捕獲并上報(bào)JS錯(cuò)誤與白屏的文章就介紹到這了,更多相關(guān)捕獲并上報(bào)JS錯(cuò)誤與白屏內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript開發(fā)隨筆二 動(dòng)態(tài)加載js和文件
js無非就是script標(biāo)簽引入頁面,但當(dāng)項(xiàng)目越來越大的時(shí)候,單頁面引入N個(gè)js顯然不行,合并為單個(gè)文件減少了請求數(shù),但請求的文件體積卻很大2011-11-11
JavaScript中的單引號和雙引號報(bào)錯(cuò)的解決方法
數(shù)據(jù)中夾雜單引號(')或者雙引號("),這種語句往往會(huì)造成JavaScript報(bào)錯(cuò)。對此一般采用/'或者/"的解決2014-09-09
可以用鼠標(biāo)拖動(dòng)的DIV實(shí)現(xiàn)思路及代碼
DIV可以拖動(dòng)的效果,想必大家都有見到過吧,在本文也為大家實(shí)現(xiàn)一個(gè)不錯(cuò)的可以用鼠標(biāo)拖動(dòng)的div,感興趣的各位不要錯(cuò)過2013-10-10
JS倒計(jì)時(shí)實(shí)例_天時(shí)分秒
下面小編就為大家?guī)硪黄狫S倒計(jì)時(shí)實(shí)例_天時(shí)分秒。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08

