2016-02-04 4 views
1

Хорошо, я могу просто пропустить очевидное, но я не могу найти общий ответ на этот вопрос, и мой Google-Fu до сих пор мне не удалось.Bluebird (или другая библиотека Promise) Сохраняйте следы следов ошибок Promise

В обработчике Catch Promise, как вы перебрасываете ошибку, сохраняя при этом трассировку стека Promise исходной ошибки?

Это, возможно, не правильное описание, так вот пример:

https://jsfiddle.net/8sgj8x4L/19/

С помощью этого кода, то прослеживается стек:

Warning: a promise was rejected with a non-error: [object String] 
    at RejectWithAnError (https://fiddle.jshell.net/_display/:51:19) 
    at https://fiddle.jshell.net/_display/:57:14 
From previous event: 
    at StartTheProgram (https://fiddle.jshell.net/_display/:56:6) 
    at window.onload (https://fiddle.jshell.net/_display/:67:1) 
bluebird.js:1444 Unhandled rejection an error occurred 

Однако, если обработчик Загвоздка добавлена, и ошибка будет повторно отвергнута или повторно выбрана из этого обработчика, тогда стек станет местом нового вызова метода отклонения:

https://jsfiddle.net/8sgj8x4L/18/

Какие следы этой трассировки стека:

Warning: a promise was rejected with a non-error: [object String] 
    at https://fiddle.jshell.net/_display/:65:23 
From previous event: 
    at StartTheProgram (https://fiddle.jshell.net/_display/:61:11) 
    at window.onload (https://fiddle.jshell.net/_display/:70:1) 
bluebird.js:1444 Unhandled rejection an error occurred 

Вы можете увидеть внутренний метод, который переданную первоначальную ошибку, «RejectWithAnError», исчезает из второго стека, так как была поймана ошибка и вновь брошен.

Для справки, вот полный код из JSFiddle (Новейший Bluebird упоминается в качестве внешней зависимости):

window.P.longStackTraces(); 

function RejectWithAnError() { 
     var err = {error: true, message: "an error occurred"}; 
     err.prototype = new Error(); 
     return window.P.reject(err); 
} 

function StartTheProgram() { 
    return RejectWithAnError() 

    // Comment out this catch handler completely, and the Promise stack trace will correctly show the "RejectWithAnError" method as the error origin. 
    .catch(function (status) { 
      console.log("[WARN] Catch handler was called."); 
      // Neither of these lines will show "RejectWithAnError" in the Promise chain stack trace. 
      // throw status; 
      return window.P.reject(status); 

    }); 
} 

StartTheProgram() 

(На стороне записки, это мой первый Stack Overflow вопрос, так что я надеюсь, что это правильный формат для этого вопроса.)

Редактировать: Обновлен пример отказа от использования экземпляра объекта, который наследуется от нового экземпляра Error.

+0

Sidenote: Всегда отклонять экземпляр конструктора 'Error'. –

+0

'status' является строкой и не может хранить информацию о стеке. Вот почему вы всегда должны использовать объекты 'Error'. – Bergi

+0

Спасибо за указатель. Я обновил JSFiddle, чтобы использовать экземпляр Error: [https://jsfiddle.net/8sgj8x4L/12/](https://jsfiddle.net/8sgj8x4L/12/) Исходная трассировка стека определенно полезна, в идеале было бы сохранить цепочку обещаний, которая привела бы к ошибке через сложные цепочки обещаний. Например, при включении длинных стеков в Bluebird вы можете увидеть все обещания, которые привели к сбою, но если я добавлю обработчик catch, он, похоже, потеряет любую информацию, прежде чем этот обработчик улова будет вызван в Promise цепь. –

ответ

2

Ошибки в JavaScript фиксируют свою трассировку , когда они созданы, поэтому всякий раз, когда вы восстанавливаете ошибку, она автоматически захватывает трассировку стека.

Вы, тем не менее, не выбрасываете ошибки. По этой причине bluebird дает вам предупреждение (yay us). Если вы настаиваете на том, чтобы бросать не-ошибки, а не правильно подклассифицировать ошибки, вам нужно вручную обмануть объект, чтобы иметь надлежащую трассировку стека, вручную захватив его. Либо путем создания new Error внутри конструктора и установки .stack его стек (возможно, придется сделать некоторые разбора), либо путем вызова конкретного метода:

function RejectWithAnError() { 
    var err = {error: true, message: "an error occurred"}; 
    // err.__proto__ = new Error(); -- this is how you'd do it with prototypes btw 
    // explicitly capture the stack trace of the object 
    if(Error.captureStackTrace) Error.captureStackTrace(err); 
} 

скрипку here. Просто примечание: .prototype - свойство , используемое функциями, чтобы указать прототип объектов, созданных вызовом функции в качестве конструктора. Чтобы установить прототип объекта напрямую, вы должны называть __proto__, хотя это редко бывает особенно хорошей идеей. Вот пример с __proto__ instead of Error.captureStackTrace.

+0

Спасибо за ответ. Я думаю, что важный взнос для меня с вашего вклада заключается в том, что я рассматриваю проблему с неправильной точки зрения. Если я хочу увидеть полную трассировку стека отладки, напечатанную Bluebird, вернемся к исходному местоположению первого Отклонения, который начал текущую цепочку отклонения, это, вероятно, проблематично; (На самом деле это похоже на что-то, что Bluebird должно было бы предоставить, эквивалент «Error.captureStackTrace (err);», но для стека вызовов асинхронного вызова, например, метод с именем «Bluebird.captureAsyncStackTrace (err);») –

+0

(Продолжение с предыдущего комментария, слишком много символов, чтобы вписаться в один комментарий.) Однако, если объект, переданный на вызов отклонения, всегда является экземпляром «Ошибка», то исходное местоположение файла, которое отправило ошибку может быть известна в любом обработчике 'catch' после этой точки в цепочке Promise, и как только это местоположение известно, тогда, вероятно, не очень важно, если завершилась трассировка невидимых исключений, напечатанная Bluebird. Опять же, спасибо за вход, это определенно полезно. –

+0

+1, но не могли бы вы продемонстрировать использование 'Object.setPrototypeOf' вместо устаревшего' __proto__'? – Bergi

0
Promise.config({ 
    warnings: false 
}); 
+2

Пожалуйста, объясните. – Bergi

Смежные вопросы