Debugging
Monkey Patch
Window State Injection
Inject trace function (log, monitor, report service)
to window pushState and replaceState.
function _wr(type) {
const orig = window.history[type]
return function (...args) {
const rv = orig.apply(this, args)
const e = new Event(type.toLowerCase())
e.arguments = args
window.dispatchEvent(e)
return rv
}
}
window.history.pushState = _wr('pushState')
window.history.replaceState = _wr('replaceState')
window.addEventListener('pushstate', (event) => {
console.trace('pushState')
})
window.addEventListener('replacestate', (event) => {
console.trace('replaceState')
})
Event Propagation Injection
const originalStopPropagation = MouseEvent.prototype.stopPropagation
MouseEvent.prototype.stopPropagation = function (...args) {
console.trace('stopPropagation')
originalStopPropagation.call(this, ...args)
}
Window Scroll Injection
let originalScrollTop = element.scrollTop
Object.defineProperty(element, 'scrollTop', {
get() {
return originalScrollTop
},
set(newVal) {
console.trace('scrollTop')
originalScrollTop = newVal
},
})
Logging
Logging Type
- Application client log.
- Web server log.
- Database server log.
- Access log.
- Debug log.
- Error log.
Logging Information
- 日志时间: 包含时区信息和毫秒.
- 日志级别.
- 会话标识.
- 功能标识.
- 精炼内容: 场景信息, 状态信息 (开始/中断/结束), 重要参数.
- 其他信息: 版本号, 线程号.
Logging Setup
const { createLogger, format, transports } = require('winston')
const logLevels = {
fatal: 0,
error: 1,
warn: 2,
info: 3,
debug: 4,
trace: 5,
}
const logger = createLogger({
levels: logLevels,
format: format.combine(format.timestamp(), format.json()),
transports: [new transports.Console()],
})
logger.info('System Started')
logger.fatal('Fatal error occurred')
Logging Clock
performance.now()is more precise (100 us).performance.now()is strictly monotonic (unaffected by changes of machine time).
let lastVisibilityChange = 0
window.addEventListener('visibilitychange', () => {
lastVisibilityChange = performance.now()
})
// don’t log any metrics started before the last visibility change
// don't log any metrics if the page is hidden
// discard perf data from when the machine was not running app at full speed
function metrics() {
if (metric.start < lastVisibilityChange || document.hidden)
return
process()
}
requestAnimationFrame(() => {
requestAnimationFrame((timestamp) => {
metric.finish(timestamp)
})
})
Console API
console.XXX.copy: copy complex object to clipboard.monitor: monitor object.
const devtools = /./
devtools.toString = function () {
this.opened = true
}
console.log('%c', devtools)
// devtools.opened will become true if/when the console is opened
// Basic console functions
console.assert()
console.clear()
console.log()
console.debug()
console.info()
console.warn()
console.error()
// Different output styles
console.dir()
console.dirxml()
console.table()
console.group()
console.groupCollapsed()
console.groupEnd()
// Trace console functions
console.trace()
console.count()
console.countReset()
console.time()
console.timeEnd()
console.timeLog()
// Non-standard console functions
console.profile()
console.profileEnd()
console.timeStamp()
console.log:
// `sprinf` style log
console.log('%d %o %s', integer, object, string)
console.log('%c ...', 'css style')
console.table:
// display array of object (tabular data)
const transactions = [
{
id: '7cb1-e041b126-f3b8',
seller: 'WAL0412',
buyer: 'WAL3023',
price: 203450,
time: 1539688433,
},
{
id: '1d4c-31f8f14b-1571',
seller: 'WAL0452',
buyer: 'WAL3023',
price: 348299,
time: 1539688433,
},
{
id: 'b12c-b3adf58f-809f',
seller: 'WAL0012',
buyer: 'WAL2025',
price: 59240,
time: 1539688433,
},
]
console.table(data, ['id', 'price'])
JavaScript Tracing API
debugger:
// debugger;
copy(obj) // to clipboard
window.onerror = function (errorMessage, scriptURI, lineNo, columnNo, error) {
console.log(`errorMessage: ${errorMessage}`) // 异常信息
console.log(`scriptURI: ${scriptURI}`) // 异常文件路径
console.log(`lineNo: ${lineNo}`) // 异常行号
console.log(`columnNo: ${columnNo}`) // 异常列号
console.log(`error: ${error}`) // 异常堆栈信息
// ...
// 异常上报
}
window.addEventListener('error', () => {
console.log(error)
// ...
// 异常上报
})
Trace Property
function traceProperty(object, property) {
let value = object[property]
Object.defineProperty(object, property, {
get() {
console.trace(`${property} requested`)
return value
},
set(newValue) {
console.trace(`setting ${property} to `, newValue)
value = newValue
},
})
}
Node Debugging API
node --inspect.- ndb.
node --inspect
ndb index.js
Chrome DevTools Detection
Console DevTools Detection
const x = document.createElement('div')
Object.defineProperty(x, 'id', {
get() {
// devtool opened.
return 'id'
},
})
console.log(x)
// eslint-disable-next-line prefer-regex-literals -- use RegExp to detect devtools panel opened
const c = new RegExp('1')
c.toString = function () {
// devtool opened
}
console.log(c)
Anti Method: hook
consoleobject, disable all outputs.
Debugger Detection
;(function () {}).constructor('debugger')()
;(() => {
function block() {
if (
window.outerHeight - window.innerHeight > 200
|| window.outerWidth - window.innerWidth > 200
) {
document.body.innerHTML = 'Debug detected, please reload page!'
}
setInterval(() => {
;(function () {
return false
})
.constructor('debugger')
.call()
}, 50)
}
try {
block()
} catch (err) {}
})()
const startTime = new Date()
// debugger;
const endTime = new Date()
const isDev = endTime - startTime > 100
while (true) {
// debugger;
}
Anti Method: use chrome protocol to block all
debuggerrequest. Anti Method: hookFunction.prototype.constructorand replacedebuggerstring.
Chrome DevTools Shortcuts
- c-d: go to next word
- c-f in
Elementspanel: search DOM node - c-m: go to next bracket
- c-p: go to files
- cs-p: go to anywhere
- cs-o: go to functions
long click reload: multiple reload options e.g. clean cache
Elements Panel
- Break on elements.
- Inspect elements a11y.
- Capture node screenshot.
Style Tab
- color picker
- filter: class filter, pseudo filter, css style filter
Console Panel
$_.$0-$4.$():document.querySelector().$$():document.querySelectorAll().getEventListeners(dom).monitorEvents(dom, events).unmonitorEvents(dom).monitor(fn).unmonitor(fn).debug(fn).undebug(fn).keys(object).values(object).queryObjects(Constructor).
Console Settings
- preserve log
- show timestamps
- Verbose: additional performance log
- click filename, filter error messages
- add folder to workspace
Capture Default Event Listener
$0: the reference to the currently selected element in the Elements panel.
const listener = getEventListeners($0).click[0].listener
$0.removeEventListener('click', listener)
$0.addEventListener('click', (e) => {
// do something
// ...
// then
listener(e)
})
Source Panel
- Add log points.
- Multiple breakpoints: source, XHR/fetch, DOM, global/event listeners.
- Open a source file, right click code,
Blackbox scriptitem. - Local Overrides for persistent changes to css styles.
Same thing in VSCode debug panel (log points, break points etc).
Network Panel
- Network throttling: simulate different network environment.
- Initiator: go to files.
Performance Panel
C+S+P: performance monitor.C+S+P: FPS.- Performance tips.
- Memory panel.
- Timeline events:
script -> style -> layout -> paint -> composite. - Timeline events reference.
- Performance analysis reference.
- Performance tools guide.
Simulation Panel
- cs-p: type
3G(slow network) - cs-p: type
sensor(geolocation)
Audit Panel
- cs-p: type
audit
Coverage Panel
- cs-p: type
coverage - Use to eliminate unused CSS/JS code.
Memory Panel
- Heap snapshot
JS Profiler Panel
Layer Panel
Tool for composite stage analysis:
- Compositor layers.
Rendering Panel
- Emulate a focused page.
- FPS monitor.
- Scrolling performance.
- Scroll event.
- Paint flashing area: re-paint area.
- Layout shift region.
- Compositor layer borders.
- CSS media query emulation:
prefers-color-scheme.prefers-reduced-motion.prefers-contrast.- A11y emulation.
Animations Panel
Overview for animations: learn animations tricks.
CSS Overview Panel
CSS overview:
- Colors.
- Fonts.
- Unused declarations.
- Media queries.
Bug List
Basic Bug
- 必须进行输入验证 - 永远不要相信用户输入.
- 永不使用未经验证的数值的长度或大小.
- 必须返回正确的错误状态.
- 注意(隐式)类型转换.
C Bug
- 栈缓冲区溢出.
- 空指针解引用.
- (隐式)类型转换.
- GOT 覆写 (Global Offset Table).
Occasional Bug
- 多进程完全异步编程的复杂性.
- 逐渐地内存泄漏.