Angular 9(v9.0.6)アプリがユニバーサル(SSR)で正常に動作していて、アプリケーションが100でハングしていることに気付いたときに、PRODに移行する前に最後のテストセットを実行していました。 %CPU消費率私はエラーを分析し、AngularアプリがHTTP呼び出しを実行する遅延ロードされたモジュールであるルートを直接ロードするときに問題であることがわかりました。
ホームを介してangular=(またはHTTPを使用しない別のルート-しかし、ホームであっても、別の遅延ロードされたモジュールがHTTP呼び出しを行う同じコンポーネントを持っている)をロードすると、正常に動作します。ナビゲートできますすべてのルートに問題なくAPPは魅力のように機能します。私が行ったとしても、新しいタブで直接www.mywebsite/lazy-loaded-moduleと言うと、bootstrapプロセスにより、すべての登録、または少なくともHTTPClientModuleが正しく登録されず、エラーが発生します。
まず、HTTPClientModule
にAppModule
を1回だけ登録しました。私が得るエラーは:
(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.
CPUが100%になり、アプリケーションがハングします。繰り返しますが、www.my-website.com
次に、アプリをナビゲートして/my-lazy-loaded-module
次に別の方法を試しました:遅延ロードされたモジュール内にHTTPClientModuleを含めると(そうすべきではないことがわかります)、CPUの問題と同様に機能しなくなりましたが、別のエラーが発生しました。
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に更新しました。これにより、バッファ警告が修正されます。アプリケーションは依然としてハングし、1つのモジュールでのみ発生します。他のモジュールもhttp呼び出しを行っています(同じ標準のgetですが、別のサービスで)問題なく。
**更新3 **
問題の根本的な原因を発見しました。最終的にはHTTPとは何の関係もありませんでした。起こっていたのは、私が言及しているページにangularアニメーションが非常にシンプルであることです。これは、標準のangularアニメーション。無限の効果を達成するために、animation.done
イベントを使用して、状態を大または小に変更します。さて、そのアニメーションが配置されているルート上のページをハードリフレッシュすると、次のような無限ループになります。
{ 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
を使用すべきであると主張することができます。
はい、angularにリクエストがSSRサーバーによって発行されていることを通知する方法を知っている場合、アニメーションを実現するより良い方法があります。
だからここに行く。
あなたはserver.tsを見ることができます
注入される注入トークンがあります。
providers: [
{ provide: APP_BASE_HREF, useValue: req.baseUrl },
今あなたがする必要があるのはコンポーネントに行き、以下のようにこのトークンを注入することです。
constructor(
@Optional() @Inject(APP_BASE_HREF) private basehref: string,
basehref
がSSRでない場合はnullになり、SSRから要求された場合は一部の文字列値になります。
basehref
がnullの場合にのみアニメーションを実行する方法を提供するようになりました。