Как получить трассировку стека ошибки при использовании rxjs?

Я использую angular-cli для создания небольшого веб-приложения angular2 и отлаживаю его с помощью инструментов разработчика Chrome.

Ясно, что я делаю что-то не так, если мне нужно каждый раз угадывать, где источник ошибки и какова трассировка стека этой ошибки.

Возьмем, к примеру, эту ошибку:

error_handler.js:45EXCEPTION: Cannot read property 'provider' of nullErrorHandler.handleError @ error_handler.js:45
error_handler.js:50ORIGINAL STACKTRACE:ErrorHandler.handleError @ error_handler.js:50
error_handler.js:51TypeError: Cannot read property 'provider' of null
    at MapSubscriber.project (auth.effects.ts:80)
    at MapSubscriber._next (map.js:77)
    at MapSubscriber.Subscriber.next (Subscriber.js:89)
    at DistinctUntilChangedSubscriber._next (distinctUntilChanged.js:72)
    at DistinctUntilChangedSubscriber.Subscriber.next (Subscriber.js:89)
    at MapSubscriber._next (map.js:83)
    at MapSubscriber.Subscriber.next (Subscriber.js:89)
    at MapSubscriber._next (map.js:83)
    at MapSubscriber.Subscriber.next (Subscriber.js:89)
    at RefCountSubscriber.Subscriber._next (Subscriber.js:125)ErrorHandler.handleError @ error_handler.js:51
zone.js:355Unhandled Promise rejection: Cannot read property 'provider' of null ; Zone: <root> ; Task: Promise.then ; Value: TypeError: Cannot read property 'provider' of null(…) TypeError: Cannot read property 'provider' of null
    at MapSubscriber.project (http://localhost:4200/main.bundle.js:35342:83)
    at MapSubscriber._next (http://localhost:4200/main.bundle.js:4171:35)
    at MapSubscriber.Subscriber.next (http://localhost:4200/main.bundle.js:395:18)
    at DistinctUntilChangedSubscriber._next (http://localhost:4200/main.bundle.js:25485:30)
    at DistinctUntilChangedSubscriber.Subscriber.next (http://localhost:4200/main.bundle.js:395:18)
    at MapSubscriber._next (http://localhost:4200/main.bundle.js:4177:26)
    at MapSubscriber.Subscriber.next (http://localhost:4200/main.bundle.js:395:18)
    at MapSubscriber._next (http://localhost:4200/main.bundle.js:4177:26)
    at MapSubscriber.Subscriber.next (http://localhost:4200/main.bundle.js:395:18)
    at RefCountSubscriber.Subscriber._next (http://localhost:4200/main.bundle.js:431:26)consoleError @ zone.js:355
zone.js:357Error: Uncaught (in promise): TypeError: Cannot read property 'provider' of null
    at resolvePromise (http://localhost:4200/main.bundle.js:93214:31)
    at http://localhost:4200/main.bundle.js:93191:13
    at ZoneDelegate.invoke (http://localhost:4200/main.bundle.js:92988:28)
    at Zone.run (http://localhost:4200/main.bundle.js:92881:43)
    at http://localhost:4200/main.bundle.js:93247:57
    at ZoneDelegate.invokeTask (http://localhost:4200/main.bundle.js:93021:37)
    at Zone.runTask (http://localhost:4200/main.bundle.js:92921:47)
    at drainMicroTaskQueue (http://localhost:4200/main.bundle.js:93153:35)consoleError @ zone.js:357 

Проблема:

Эти ошибки ничего не значат для меня. Это совершенно бесполезно и нечитаемо. Мне повезло, что я увидел эту строку (иногда я не понимаю, где ошибка): at MapSubscriber.project (auth.effects.ts:80) - Эта строка - единственная полезная здесь, чтобы понять, как исправить эту ошибку. Попытка понять трассировку стека будет бессмысленной, потому что это все трассировка стека rxjs.

Мой вопрос:

Я хотел бы узнать трассировку стека моего кода. Это возможно?

  1. где в моем коде происходит подписка на этот наблюдаемый.
  2. Если это наблюдаемое из ngrx, то где в моем коде кто-то удалил это действие, которое вызывает ошибку.

Это более общий вопрос о том, как отлаживать асинхронный код с помощью rxjs, а затем исправлять эту конкретную ошибку.


person Stav Alfi    schedule 15.10.2016    source источник


Ответы (1)


Это произошло в методе проекции, который вы предоставили оператору map. Подсказка находится наверху вашего стека. MapSubscriber.project.

В основном вы читаете трассировку стека сверху. Самый верхний вызов - это место, где была выдана ошибка (или повторно выдана).

В RxJS 5 обычно приходится два-три вызова на одного оператора. У каждого оператора есть абонент, названный в его честь, который выполняет работу. MapSubscriber.Subscriber.next MapSubscriber._next и т. д.

person Ben Lesh    schedule 16.10.2016
comment
Спасибо за информацию. По сути, вы говорите, что нет способа узнать, где в моем коде кто-то подписался на тот наблюдаемый, который вызывает ошибку? - person Stav Alfi; 16.10.2016
comment
@StavAlfi невозможно иметь стековый трек кода, которого нет в стеке, когда возникает ошибка. Когда вы вызываете subscribe, вы прослушиваете события, которые будут генерироваться. Если сразу не возникает ошибка когда вы вызываете subscribe, этого вызова нет в стеке вызовов. Если ошибка возникает внутри вашей наблюдаемой цепочки (в данном случае функции вашего проекта, которую вы предоставляете оператору карты), она никогда не достигает вашего наблюдателя; обратный вызов, который вы предоставили для подписки, снова не находится в стеке. - person jayphelps; 19.10.2016
comment
Хорошо, спасибо @JayPhelps. Я надеюсь, что вы, ребята, создадите дополнительный стек, содержащий только асинхронные операции, чтобы было легче отлаживать и получать больше контроля. - person Stav Alfi; 19.10.2016
comment
Можете ли вы уточнить, что было бы идеальным? Мы очень усердно работали, чтобы сделать различные возможные стеки значительно более понятными, чем они были в v4, и не ясно, как мы могли бы их значительно улучшить. Возможно, есть недоразумение? - person jayphelps; 19.10.2016
comment
Когда ваш Observable испускает элементы, этот стек не связан со стеком, в котором вы определили поток с помощью таких операторов, как observable.debounceTime(100).map(i => i + 1) и т. д. Когда вы вызываете операторы, это в основном настройка каналов, а операторы похожи на инструкции, говорящие Rx делать это для каждого предмет излучается всякий раз, когда они прибывают. Это отличается от методов массива array.map(i => i + 1), потому что с массивом вы работаете со значениями прямо сейчас, потому что они существуют синхронно. В то время как элементы, которые испускает ваш Observable [обычно], приходят в будущем, async. - person jayphelps; 19.10.2016
comment
@JayPhelps Спасибо за внимание. Позвольте мне перефразировать себя. Я хотел бы предложить вам, ребята, создать новый компонент, демонстрирующий стек функций, которые rxjs выполняет при возникновении ошибки. например код: `Observable.from([1,2,3]).map(num=›num+1).do(_=›сбросить мою ошибку); => это будет отображаться в стеке компонентов как rxFile строка X -> rxFile строка X+5 -> .... ошибка в rxFile строка X +80. Таким образом, я могу легко найти, что сломано и почему (точки останова не будут, но в списке мы получим некоторый контроль). Надеюсь, я ясно выразился. Большое спасибо! - person Stav Alfi; 19.10.2016