diff --git a/doc/UTIL_API.md b/doc/UTIL_API.md index 63a710a..5eb2d8f 100644 --- a/doc/UTIL_API.md +++ b/doc/UTIL_API.md @@ -2555,6 +2555,41 @@ ucs2.decode('abc'); // -> [0x61, 0x62, 0x63] ucs2.decode('𝌆').length; // -> 1 ``` +## uncaught + +Handle global uncaught errors and promise rejections. + +### start + +Start handling of errors. + +### stop + +Stop handling. + +### addListener + +Add listener for handling errors. + +|Name|Type |Desc | +|----|--------|--------------| +|fn |function|Error listener| + +### rmListener + +Remove listener. + +### rmAllListeners + +Remove all listeners. + +```javascript +uncaught.start(); +uncaught.addListener(err => { + // Do something. +}); +``` + ## uniqId Generate a globally-unique id. diff --git a/src/Console/Console.js b/src/Console/Console.js index a26570c..ce39aaa 100644 --- a/src/Console/Console.js +++ b/src/Console/Console.js @@ -1,10 +1,12 @@ import Logger from './Logger' import Tool from '../DevTools/Tool' -import { noop, evalCss, $, Emitter } from '../lib/util' +import { noop, evalCss, $, Emitter, uncaught } from '../lib/util' import emitter from '../lib/emitter' import Settings from '../Settings/Settings' import stringify from './stringify' +uncaught.start() + export default class Console extends Tool { constructor() { super() @@ -24,7 +26,7 @@ export default class Console extends Tool { this._initLogger() this._exposeLogger() - this._rejectionHandler = e => this._logger.error(e.reason) + this._errHandler = err => this._logger.error(err) this._initCfg() this._bindEvent() @@ -58,21 +60,12 @@ export default class Console extends Tool { return this } catchGlobalErr() { - this._origOnerror = window.onerror - - window.onerror = (errMsg, url, lineNum, column, errObj) => { - this._logger.error(errObj ? errObj : errMsg) - } - window.addEventListener('unhandledrejection', this._rejectionHandler) + uncaught.addListener(this._errHandler) return this } ignoreGlobalErr() { - if (this._origOnerror) { - window.onerror = this._origOnerror - delete this._origOnerror - } - window.removeEventListener('unhandledrejection', this._rejectionHandler) + uncaught.rmListener(this._errHandler) return this } @@ -141,11 +134,11 @@ export default class Console extends Tool { } _bindEvent() { const container = this._container - const $input = this._$input, - $inputBtns = this._$inputBtns, - $control = this._$control, - logger = this._logger, - config = this.config + const $input = this._$input + const $inputBtns = this._$inputBtns + const $control = this._$control + const logger = this._logger + const config = this.config $control .on('click', '.eruda-clear-console', () => logger.silentClear()) diff --git a/src/lib/util.js b/src/lib/util.js index fdca8f1..ed4a86a 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -2222,20 +2222,20 @@ export var isErr = _.isErr = (function (exports) { /* ------------------------------ isErudaEl ------------------------------ */ export var isErudaEl = _.isErudaEl = (function (exports) { - /* See if an element is within eruda. - */ + /* See if an element is within eruda. + */ - exports = function(el) { - let parentNode = el.parentNode + exports = function(el) { + let parentNode = el.parentNode - if (!parentNode) return false + if (!parentNode) return false - while (parentNode) { - parentNode = parentNode.parentNode - if (parentNode && parentNode.id === 'eruda') return true - } + while (parentNode) { + parentNode = parentNode.parentNode + if (parentNode && parentNode.id === 'eruda') return true + } - return false + return false } return exports; @@ -3245,54 +3245,54 @@ export var difference = _.difference = (function (exports) { /* ------------------------------ evalCss ------------------------------ */ export var evalCss = _.evalCss = (function (exports) { - /* Eval css. + /* Eval css. */ /* dependencies * toStr each filter - */ + */ - let styleList = [] - let scale = 1 + let styleList = [] + let scale = 1 - exports = function(css, container) { - css = toStr(css) + exports = function(css, container) { + css = toStr(css) - for (let i = 0, len = styleList.length; i < len; i++) { - if (styleList[i].css === css) return - } + for (let i = 0, len = styleList.length; i < len; i++) { + if (styleList[i].css === css) return + } - container = container || exports.container || document.head - const el = document.createElement('style') + container = container || exports.container || document.head + const el = document.createElement('style') - el.type = 'text/css' - container.appendChild(el) + el.type = 'text/css' + container.appendChild(el) - let style = { css, el, container } - resetStyle(style) - styleList.push(style) + let style = { css, el, container } + resetStyle(style) + styleList.push(style) - return style - } + return style + } - exports.setScale = function(s) { - scale = s - each(styleList, style => resetStyle(style)) - } + exports.setScale = function(s) { + scale = s + each(styleList, style => resetStyle(style)) + } - exports.clear = function() { - each(styleList, ({ container, el }) => container.removeChild(el)) - styleList = [] - } + exports.clear = function() { + each(styleList, ({ container, el }) => container.removeChild(el)) + styleList = [] + } - exports.remove = function(style) { - styleList = filter(styleList, s => s !== style) + exports.remove = function(style) { + styleList = filter(styleList, s => s !== style) - style.container.removeChild(style.el) - } + style.container.removeChild(style.el) + } - function resetStyle({ css, el }) { - el.innerText = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px') + function resetStyle({ css, el }) { + el.innerText = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px') } return exports; @@ -8150,6 +8150,104 @@ export var tryIt = _.tryIt = (function (exports) { return exports; })({}); +/* ------------------------------ uncaught ------------------------------ */ + +export var uncaught = _.uncaught = (function (exports) { + /* Handle global uncaught errors and promise rejections. + * + * ### start + * + * Start handling of errors. + * + * ### stop + * + * Stop handling. + * + * ### addListener + * + * Add listener for handling errors. + * + * |Name|Type |Desc | + * |----|--------|--------------| + * |fn |function|Error listener| + * + * ### rmListener + * + * Remove listener. + * + * ### rmAllListeners + * + * Remove all listeners. + */ + + /* example + * uncaught.start(); + * uncaught.addListener(err => { + * // Do something. + * }); + */ + + /* typescript + * export declare const uncaught: { + * start(): void; + * stop(): void; + * addListener(fn: (err: Error) => void): void; + * rmListener(fn: (err: Error) => void): void; + * rmAllListeners(): void; + * }; + */ + + /* dependencies + * isBrowser + */ + + var listeners = []; + var isOn = false; + exports = { + start: function() { + isOn = true; + }, + stop: function() { + isOn = false; + }, + addListener: function(fn) { + listeners.push(fn); + }, + rmListener: function(fn) { + var idx = listeners.indexOf(fn); + + if (idx > -1) { + listeners.splice(idx, 1); + } + }, + rmAllListeners: function() { + listeners = []; + } + }; + + if (isBrowser) { + window.addEventListener('error', function(event) { + callListeners(event.error); + }); + window.addEventListener('unhandledrejection', function(e) { + callListeners(e.reason); + }); + } else { + process.on('uncaughtException', callListeners); + process.on('unhandledRejection', callListeners); + } + + function callListeners(err) { + if (!isOn) return; + + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i](err); + } + } + + return exports; +})({}); + /* ------------------------------ uniqId ------------------------------ */ export var uniqId = _.uniqId = (function (exports) { diff --git a/test/util.js b/test/util.js index 14fe619..c7f9293 100644 --- a/test/util.js +++ b/test/util.js @@ -1831,54 +1831,54 @@ /* ------------------------------ evalCss ------------------------------ */ _.evalCss = (function (exports) { - /* Eval css. + /* Eval css. */ /* dependencies * toStr each filter - */ + */ - let styleList = [] - let scale = 1 + let styleList = [] + let scale = 1 - exports = function(css, container) { - css = toStr(css) + exports = function(css, container) { + css = toStr(css) - for (let i = 0, len = styleList.length; i < len; i++) { - if (styleList[i].css === css) return - } + for (let i = 0, len = styleList.length; i < len; i++) { + if (styleList[i].css === css) return + } - container = container || exports.container || document.head - const el = document.createElement('style') + container = container || exports.container || document.head + const el = document.createElement('style') - el.type = 'text/css' - container.appendChild(el) + el.type = 'text/css' + container.appendChild(el) - let style = { css, el, container } - resetStyle(style) - styleList.push(style) + let style = { css, el, container } + resetStyle(style) + styleList.push(style) - return style - } + return style + } - exports.setScale = function(s) { - scale = s - each(styleList, style => resetStyle(style)) - } + exports.setScale = function(s) { + scale = s + each(styleList, style => resetStyle(style)) + } - exports.clear = function() { - each(styleList, ({ container, el }) => container.removeChild(el)) - styleList = [] - } + exports.clear = function() { + each(styleList, ({ container, el }) => container.removeChild(el)) + styleList = [] + } - exports.remove = function(style) { - styleList = filter(styleList, s => s !== style) + exports.remove = function(style) { + styleList = filter(styleList, s => s !== style) - style.container.removeChild(style.el) - } + style.container.removeChild(style.el) + } - function resetStyle({ css, el }) { - el.innerText = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px') + function resetStyle({ css, el }) { + el.innerText = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px') } return exports;