Ответ 1
Я не знаю такого нативного метода, как Java, и я пока не нашел элегантного решения для упаковки ошибок.
Проблема с созданием new Error
заключается в том, что вы можете потерять метаданные, которые были прикреплены к исходной Error
которая была выдана, стек и тип, как правило, элементы теряются.
Внесение изменений в существующую сгенерированную ошибку происходит быстрее, но все же можно изменить данные об ошибке в случае ее отсутствия. Также кажется неправильным возиться с ошибкой, которая была создана где-то еще.
Создать новую ошибку и новый стек
Свойство .stack
новой Error
является простой строкой и может быть изменено, чтобы сказать, что вам нравится, до того, как оно будет выдано. Однако полная замена свойства stack
ошибок может привести к путанице при отладке.
Когда исходная сгенерированная ошибка и ее обработчик находятся в разных местах или файлах (что часто встречается в обещаниях), вы можете отследить источник исходной ошибки, но не отследить обработчик, в котором ошибка была фактически перехвачена. Чтобы избежать этого, полезно хранить в stack
некоторые ссылки как на исходную, так и на новую ошибку. Также полезно иметь доступ к полной исходной ошибке, если в ней хранятся дополнительные метаданные.
Вот пример перехвата ошибки, ее переноса в новую ошибку, но с добавлением исходного stack
и сохранением error
:
try {
throw new Error('First one')
} catch (error) {
let e = new Error('Rethrowing the "${error.message}" error')
e.original = error
e.stack = e.stack.split('\n').slice(0,2).join('\n') + '\n' +
error.stack
throw e
}
Который бросает:
/so/42754270/test.js:9
throw e
^
Error: Rethrowing the "First one" error
at test (/so/42754270/test.js:5:13)
Error: First one
at test (/so/42754270/test.js:3:11)
at Object.<anonymous> (/so/42754270/test.js:13:1)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
Итак, мы создали новую общую Error
. К сожалению, тип исходной ошибки становится скрытым из выходных данных, но error
была прикреплена как .original
так что к ней все еще можно получить доступ. Новый stack
был в значительной степени удален, за исключением важной строки генерации и добавления исходного stack
ошибок.
Любые инструменты, которые пытаются проанализировать трассировки стека, могут не работать с этим изменением или в лучшем случае, они обнаруживают две ошибки.
Классы ошибок ES2015
Превращаем это в повторно используемый класс ошибок ES2015+...
// Standard error extender from @deployable/errors
class ExtendedError extends Error {
constructor(message){
super(message)
this.name = this.constructor.name
this.message = message
if (typeof Error.captureStackTrace === 'function'){
Error.captureStackTrace(this, this.constructor)
} else {
this.stack = (new Error(message)).stack
}
}
}
class RethrownError extends ExtendedError {
constructor(message, error){
super(message)
if (!error) throw new Error('RethrownError requires a message and error')
this.original = error
this.new_stack = this.stack
let message_lines = (this.message.match(/\n/g)||[]).length + 1
this.stack = this.stack.split('\n').slice(0, message_lines+1).join('\n') + '\n' +
error.stack
}
}
throw new RethrownError('Oh no a "${error.message}" error', error)
Результаты в
/so/42754270/test2.js:31
throw new RethrownError('Oh no a "${error.message}"" error', error)
^
RethrownError: Oh no a "First one" error
at test (/so/42754270/test2.js:31:11)
Error: First one
at test (/so/42754270/test2.js:29:11)
at Object.<anonymous> (/so/42754270/test2.js:35:1)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
Затем вы знаете, что всякий раз, когда вы видите RethrownError
, исходная ошибка все равно будет доступна на .original
.
Этот метод не идеален, но это означает, что я могу перепечатывать известные ошибки из базовых модулей в универсальные типы, которые легче обрабатывать, обычно с отфильтрованным уловом .catch(TypeError, handler)
птиц .catch(TypeError, handler)
Та же ошибка с измененным стеком
Иногда вам нужно сохранить исходную ошибку в основном как есть.
В этом случае вы можете просто добавить/вставить новую информацию в существующий стек.
file = '/home/jim/plumbers'
try {
JSON.parse('k')
} catch (e) {
let message = 'JSON parse error in ${file}'
let stack = new Error(message).stack
e.stack = e.stack + '\nFrom previous ' + stack.split('\n').slice(0,2).join('\n') + '\n'
throw e
}
Который возвращается
/so/42754270/throw_error_replace_stack.js:13
throw e
^
SyntaxError: Unexpected token k in JSON at position 0
at Object.parse (native)
at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:8:13)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
From previous Error: JSON parse error in "/home/jim/plumbers"
at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:11:20)
Также обратите внимание, что обработка стека проста и предполагает, что сообщение об ошибке состоит из одной строки. Если вы сталкиваетесь с многострочными сообщениями об ошибках, вам может понадобиться поискать \n at
для завершения сообщения.