У меня есть приложение Angular 9 (v9.0.6), работающее корректно с Universal (SSR), и я выполнял последний набор тестов перед переходом на PROD, когда заметил, что приложение зависло со 100% -ной загрузкой ЦП. Я проанализировал ошибку и оказался проблемой, когда приложение Angular загружает напрямую маршрут, который является лениво загруженным модулем, который выполняет HTTP-вызов.
Если я загружаю angular через Home (или другой маршрут без HTTP - но даже дома, другой лениво загруженный модуль имеет тот же компонент, который выполняет HTTP-вызов), все работает нормально. Я могу перемещаться по всем маршрутам без каких-либо проблем, и приложение работает как шарм. Если, однако, я go, скажем, www.mywebsite/lazy-loaded-module прямо в новой вкладке, я полагаю, что в процессе bootstrap есть что-то, что препятствует правильной регистрации всех регистраций или, по крайней мере, модуля HTTPClientModule, а затем я получить ошибку.
Для начала, я зарегистрировал HTTPClientModule
только один раз в AppModule
. Я получаю ошибку:
(node:17624) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
Процессор переходит на 100%, и приложение зависает. Опять же, этого не произойдет, если я go до www.my-website.com
, тогда я перейду через приложение к /my-lazy-loaded-module
Я попробовал что-то еще: включение (я знаю, что не должен) HTTPClientModule внутри моего модуль с отложенной загрузкой, и он работал так же, как и в случае проблемы с процессором, исчез, однако я получил другую ошибку:
ReferenceError: XMLHttpRequest is not defined
at BrowserXhr.build
, которая влияет на контент, который я бы извлек с использованием SSR и рендеринга, потому что его нет. Как обходной путь, который мог бы сделать это, но я хотел бы знать, как это должно быть решено. Версия node
, которую я выполняю: v10.16.2
ОБНОВЛЕНИЕ
Для большей наглядности вокруг выполняемого мной HTTP-вызова это просто стандартный вызов:
public getNext = (page: number, pageSize: number): Promise<IEventsPaged> => {
return this.http.get<IEventsPaged>(`${environment.apiBaseUrl}/events?page=${page}&pageSize=${pageSize})
.toPromise()
.then(r => r)
.catch((error: Response | any) => {
return Promise.reject(error);
});
}
ОБНОВЛЕНИЕ 2
Я обновился до Angular 9.1.1, в котором исправлено предупреждение о буфере. Приложение все еще зависает, и это происходит только на одном модуле. Другие модули также выполняют HTTP-вызов (тот же стандартный get, но с другим сервисом) без проблем.
** ОБНОВЛЕНИЕ 3 **
Я нашел причину root вопрос. В конечном итоге это не имеет ничего общего с HTTP. Происходило то, что на странице, на которую я ссылаюсь, анимация angular очень простая. Это треугольник, который становится больше или меньше, применяя бесконечную анимацию с помощью стандартной angular анимации. Чтобы достичь бесконечного эффекта, я подключился к событию animation.done
, чтобы изменить состояние на большое или маленькое. Что ж, если вы жестко обновите sh страницу на том маршруте, где размещена эта анимация, вы получите бесконечное число l oop, например:
{ element:
HTMLDivElement {
parentNode:
HTMLUnknownElement {
parentNode: [HTMLDivElement],
_previousSibling: [HTMLDivElement],
_nextSibling: [HTMLImageElement],
_index: undefined,
_childNodes: null,
_firstChild: [Circular],
nodeType: 1,
ownerDocument: [Object],
localName: 'app-bottom-angle',
namespaceURI: 'http://www.w3.org/1999/xhtml',
prefix: null,
_tagName: undefined,
_attrsByQName: [Object],
_attrsByLName: [Object],
_attrKeys: [Array],
__ngContext__: [LComponentView_CalendarIntroductionComponent],
_classList: [DOMTokenList],
_nid: 79 },
_previousSibling: [Circular],
_nextSibling: [Circular],
_index: undefined,
_childNodes: null,
_firstChild: null,
nodeType: 1,
ownerDocument:
{ parentNode: null,
_previousSibling: [Circular],
_nextSibling: [Circular],
_index: undefined,
_childNodes: null,
_firstChild: [Object],
nodeType: 9,
isHTML: true,
_address: 'http://localhost:54818/en/calendar',
readyState: 'loading',
implementation: [Object],
ownerDocument: null,
_contentType: 'text/html',
doctype: [Object],
documentElement: [HTMLHtmlElement],
_templateDocCache: null,
_nodeIterators: null,
_nid: 1,
_nextnid: 152,
_nodes: [Array],
byId: [Object],
modclock: 23,
_scripting_enabled: true,
defaultView: [Object],
_lastModTime: 1 },
localName: 'div',
namespaceURI: 'http://www.w3.org/1999/xhtml',
prefix: null,
_tagName: undefined,
_attrsByQName:
[Object: null prototype] { '_ngcontent-sc33': [Object], class: [Object], style: [Object] },
_attrsByLName:
[Object: null prototype] {
'|_ngcontent-sc33': [Object],
'|class': [Object],
'|style': [Object] },
_attrKeys: [ '|_ngcontent-sc33', '|class', '|style' ],
_classList:
DOMTokenList {
'0': 'position-absolute',
'1': 'z-index-plus-1',
'2': 'bottom-0',
'3': 'right-0',
'4': 'left-0',
'5': 'mb-4',
'6': 'ng-tns-c33-1',
'7': 'ng-trigger',
'8': 'ng-trigger-scale',
'9': undefined,
'10': undefined,
_getString: [Function],
_setString: [Function],
_length: 9 },
__ngContext__:
LComponentView_BottomAngleComponent [
[HTMLUnknownElement],
[TView],
211,
[LComponentView_CalendarIntroductionComponent],
null,
null,
[TNode$1],
[LCleanup],
[BottomAngleComponent],
[Object],
[AnimationRendererFactory],
[AnimationRenderer],
null,
null,
null,
[LComponentView_CalendarIntroductionComponent],
[Circular],
null,
0,
[Circular],
'big' ],
_nid: 80,
_style:
{ _element: [Circular],
_parsedStyles: [Object],
_lastParsedText: 'transform: scale(1); transform-style: preserve-3d;',
_names: [Array] } },
triggerName: 'scale',
fromState: 'small',
toState: 'big',
phaseName: 'done',
totalTime: 1200,
disabled: false,
_data: 1006 }
{ element:
HTMLDivElement {
parentNode:
HTMLUnknownElement {
parentNode: [HTMLDivElement],
_previousSibling: [HTMLDivElement],
_nextSibling: [HTMLImageElement],
_index: undefined,
_childNodes: null,
_firstChild: [Circular],
nodeType: 1,
ownerDocument: [Object],
localName: 'app-bottom-angle',
namespaceURI: 'http://www.w3.org/1999/xhtml',
prefix: null,
_tagName: undefined,
_attrsByQName: [Object],
_attrsByLName: [Object],
_attrKeys: [Array],
__ngContext__: [LComponentView_CalendarIntroductionComponent],
_classList: [DOMTokenList],
_nid: 79 },
_previousSibling: [Circular],
_nextSibling: [Circular],
_index: undefined,
_childNodes: null,
_firstChild: null,
nodeType: 1,
ownerDocument:
{ parentNode: null,
_previousSibling: [Circular],
_nextSibling: [Circular],
_index: undefined,
_childNodes: null,
_firstChild: [Object],
nodeType: 9,
isHTML: true,
_address: 'http://localhost:54818/en/calendar',
readyState: 'loading',
implementation: [Object],
ownerDocument: null,
_contentType: 'text/html',
doctype: [Object],
documentElement: [HTMLHtmlElement],
_templateDocCache: null,
_nodeIterators: null,
_nid: 1,
_nextnid: 152,
_nodes: [Array],
byId: [Object],
modclock: 23,
_scripting_enabled: true,
defaultView: [Object],
_lastModTime: 1 },
localName: 'div',
namespaceURI: 'http://www.w3.org/1999/xhtml',
prefix: null,
_tagName: undefined,
_attrsByQName:
[Object: null prototype] { '_ngcontent-sc33': [Object], class: [Object], style: [Object] },
_attrsByLName:
[Object: null prototype] {
'|_ngcontent-sc33': [Object],
'|class': [Object],
'|style': [Object] },
_attrKeys: [ '|_ngcontent-sc33', '|class', '|style' ],
_classList:
DOMTokenList {
'0': 'position-absolute',
'1': 'z-index-plus-1',
'2': 'bottom-0',
'3': 'right-0',
'4': 'left-0',
'5': 'mb-4',
'6': 'ng-tns-c33-1',
'7': 'ng-trigger',
'8': 'ng-trigger-scale',
'9': undefined,
'10': undefined,
_getString: [Function],
_setString: [Function],
_length: 9 },
__ngContext__:
LComponentView_BottomAngleComponent [
[HTMLUnknownElement],
[TView],
211,
[LComponentView_CalendarIntroductionComponent],
null,
null,
[TNode$1],
[LCleanup],
[BottomAngleComponent],
[Object],
[AnimationRendererFactory],
[AnimationRenderer],
null,
null,
null,
[LComponentView_CalendarIntroductionComponent],
[Circular],
null,
0,
[Circular],
'small' ],
_nid: 80,
_style:
{ _element: [Circular],
_parsedStyles: [Object],
_lastParsedText: 'transform: scale(1.2); transform-style: preserve-3d;',
_names: [Array] } },
triggerName: 'scale',
fromState: 'big',
toState: 'small',
phaseName: 'done',
totalTime: 1200,
disabled: false,
_data: 1007 }
И ваше приложение зависает. Я не знаю, есть ли лучший способ достижения бесконечной анимации с использованием Angular анимаций и должен ли разработчик "знать", что SSR будет уязвим для них. Я думаю, если вы думаете, что они имеют дело с HTML элементами, вы можете утверждать, что они все должны использовать isPlatformBrowser
внутри них.