#javascript #angular #google-chrome-devtools #rxjs #angular-cli
#javascript #angular #google-chrome-devtools #rxjs #angular-cli
Вопрос:
Я использую angular-cli для создания небольшого веб-приложения angular2 и отлаживаю его с помощью chrome dev-tools.
Очевидно, что я делаю что-то не так, если мне нужно каждый раз угадывать, где источник ошибки и какова трассировка стека этой ошибки.
Возьмем, к примеру, эту ошибку:
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.
Мой вопрос:
Я хотел бы знать трассировку стека моего кода. Возможно ли это?
- где в моем коде происходит подписка на это наблюдаемое.
- Если это наблюдаемое из ngrx, то где в моем коде кто-то отклонил это действие, которое вызывает ошибку.
Это более общий вопрос о том, как отлаживать асинхронный код с помощью rxjs, а затем исправлять эту конкретную ошибку.
Ответ №1:
Это произошло в методе проекции, который вы предоставили map
оператору. Ключ находится в верхней части вашего стека. MapSubscriber.project
.
В основном вы читаете трассировки стека сверху. Самый верхний вызов — это то, где ошибка была выдана (или повторно отброшена).
В RxJS 5 обычно выполняется два или три вызова для каждого оператора. У каждого оператора есть подписчик, названный в его честь, который выполняет работу. MapSubscriber.Subscriber.next
MapSubscriber._next
и т. д
Комментарии:
1. спасибо за информацию. По сути, вы говорите, что нет способа узнать, где в моем коде кто-то подписался на это наблюдаемое, которое вызывает ошибку?
2. @StavAlfi невозможно иметь трек стека кода, которого нет в стеке при возникновении ошибки. При вызове вы
subscribe
прослушиваете события, которые будут отправлены. Если при вызове subscribe сразу не возникает ошибка, этот вызов не находится в стеке вызовов. Если ошибка возникает внутри вашей наблюдаемой цепочки (в данном случае вашей проектной функции, которую вы предоставляете оператору map), она никогда не достигает вашего наблюдателя; обратный вызов, который вы предоставили для подписки, так что, опять же, его тоже нет в стеке.3. Хорошо, спасибо @JayPhelps. Я надеюсь, что вы, ребята, создадите дополнительный стек, содержащий только асинхронные операции, чтобы его было легче отлаживать и получать больше контроля.
4. Можете ли вы уточнить, что было бы идеально? Мы очень усердно работали, чтобы сделать различные возможные стеки значительно более понятными, чем они были в версии 4, и неясно, как мы могли бы их значительно улучшить. Возможно, это недоразумение?
5. Когда ваш наблюдаемый объект выдает элементы, этот стек не связан со стеком, в котором вы определили поток с помощью таких операторов, как
observable.debounceTime(100).map(i => i 1)
etc. Когда вы вызываете операторы, это в основном настройка «каналов», а операторы похожи на инструкции, указывающие Rx делать это для каждого отправленного элемента, когда бы они ни поступали. Это отличается от методов массиваarray.map(i => i 1)
, потому что с массивом вы работаете со значениями прямо сейчас , потому что они существуют синхронно. В то время как элементы, которые ваш наблюдаемый выдает [обычно], приходят в будущем, асинхронно.