Skip to content

Commit c5e30f1

Browse files
alan-agius4dylhunn
authored andcommitted
perf(http): reduce data transfer when using HTTP caching (angular#52347)
This commit reduces the property size in the http transfer cache to reduce the page payload. Before ```html <script id="ng-state" type="application/json"> { "4155228514": { "body": "....", "headers": {}, "status": 200, "statusText": "OK", "url": "http://foo.com/assets/media.json", "responseType": "json" }, } </script> ``` Now ```html <script id="ng-state" type="application/json"> { "4155228514": { "b": "....", "h": {}, "s": 200, "st": "OK", "u": "http://foo.com/assets/media.json", "rt": "json" }, } </script> ``` PR Close angular#52347
1 parent 5436890 commit c5e30f1

File tree

3 files changed

+78
-34
lines changed

3 files changed

+78
-34
lines changed

packages/common/http/src/transfer_cache.ts

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,31 @@ export type HttpTransferCacheOptions = {
3535
includePostRequests?: boolean
3636
};
3737

38+
/**
39+
* Keys within cached response data structure.
40+
*/
41+
42+
export const BODY = 'b';
43+
export const HEADERS = 'h';
44+
export const STATUS = 's';
45+
export const STATUS_TEXT = 'st';
46+
export const URL = 'u';
47+
export const RESPONSE_TYPE = 'rt';
48+
49+
3850
interface TransferHttpResponse {
39-
body: any;
40-
headers: Record<string, string[]>;
41-
status?: number;
42-
statusText?: string;
43-
url?: string;
44-
responseType?: HttpRequest<unknown>['responseType'];
51+
/** body */
52+
[BODY]: any;
53+
/** headers */
54+
[HEADERS]: Record<string, string[]>;
55+
/** status */
56+
[STATUS]?: number;
57+
/** statusText */
58+
[STATUS_TEXT]?: string;
59+
/** url */
60+
[URL]?: string;
61+
/** responseType */
62+
[RESPONSE_TYPE]?: HttpRequest<unknown>['responseType'];
4563
}
4664

4765
interface CacheOptions extends HttpTransferCacheOptions {
@@ -82,22 +100,30 @@ export function transferCacheInterceptorFn(
82100
}
83101

84102
if (response) {
103+
const {
104+
[BODY]: undecodedBody,
105+
[RESPONSE_TYPE]: responseType,
106+
[HEADERS]: httpHeaders,
107+
[STATUS]: status,
108+
[STATUS_TEXT]: statusText,
109+
[URL]: url
110+
} = response;
85111
// Request found in cache. Respond using it.
86-
let body: ArrayBuffer|Blob|string|undefined = response.body;
112+
let body: ArrayBuffer|Blob|string|undefined = undecodedBody;
87113

88-
switch (response.responseType) {
114+
switch (responseType) {
89115
case 'arraybuffer':
90-
body = new TextEncoder().encode(response.body).buffer;
116+
body = new TextEncoder().encode(undecodedBody).buffer;
91117
break;
92118
case 'blob':
93-
body = new Blob([response.body]);
119+
body = new Blob([undecodedBody]);
94120
break;
95121
}
96122

97123
// We want to warn users accessing a header provided from the cache
98124
// That HttpTransferCache alters the headers
99125
// The warning will be logged a single time by HttpHeaders instance
100-
let headers = new HttpHeaders(response.headers);
126+
let headers = new HttpHeaders(httpHeaders);
101127
if (typeof ngDevMode === 'undefined' || ngDevMode) {
102128
// Append extra logic in dev mode to produce a warning when a header
103129
// that was not transferred to the client is accessed in the code via `get`
@@ -110,9 +136,9 @@ export function transferCacheInterceptorFn(
110136
new HttpResponse({
111137
body,
112138
headers,
113-
status: response.status,
114-
statusText: response.statusText,
115-
url: response.url,
139+
status,
140+
statusText,
141+
url,
116142
}),
117143
);
118144
}
@@ -123,12 +149,12 @@ export function transferCacheInterceptorFn(
123149
tap((event: HttpEvent<unknown>) => {
124150
if (event instanceof HttpResponse) {
125151
transferState.set<TransferHttpResponse>(storeKey, {
126-
body: event.body,
127-
headers: getFilteredHeaders(event.headers, headersToInclude),
128-
status: event.status,
129-
statusText: event.statusText,
130-
url: event.url || '',
131-
responseType: req.responseType,
152+
[BODY]: event.body,
153+
[HEADERS]: getFilteredHeaders(event.headers, headersToInclude),
154+
[STATUS]: event.status,
155+
[STATUS_TEXT]: event.statusText,
156+
[URL]: event.url || '',
157+
[RESPONSE_TYPE]: req.responseType,
132158
});
133159
}
134160
}),

packages/common/http/test/transfer_cache_spec.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {withBody} from '@angular/private/testing';
1414
import {BehaviorSubject} from 'rxjs';
1515

1616
import {HttpClient, HttpResponse, provideHttpClient} from '../public_api';
17-
import {withHttpTransferCache} from '../src/transfer_cache';
17+
import {BODY, HEADERS, RESPONSE_TYPE, STATUS, STATUS_TEXT, URL, withHttpTransferCache} from '../src/transfer_cache';
1818
import {HttpTestingController, provideHttpClientTesting} from '../testing';
1919

2020
interface RequestParams {
@@ -84,7 +84,7 @@ describe('TransferCache', () => {
8484
makeRequestAndExpectOne('/test', 'foo');
8585
const key = makeStateKey('432906284');
8686
const transferState = TestBed.inject(TransferState);
87-
expect(transferState.get(key, null)).toEqual(jasmine.objectContaining({body: 'foo'}));
87+
expect(transferState.get(key, null)).toEqual(jasmine.objectContaining({[BODY]: 'foo'}));
8888
});
8989

9090
it('should stop storing HTTP calls in `TransferState` after application becomes stable',
@@ -101,20 +101,20 @@ describe('TransferCache', () => {
101101
const transferState = TestBed.inject(TransferState);
102102
expect(JSON.parse(transferState.toJson()) as Record<string, unknown>).toEqual({
103103
'3706062792': {
104-
'body': 'foo',
105-
'headers': {},
106-
'status': 200,
107-
'statusText': 'OK',
108-
'url': '/test-1',
109-
'responseType': 'json'
104+
[BODY]: 'foo',
105+
[HEADERS]: {},
106+
[STATUS]: 200,
107+
[STATUS_TEXT]: 'OK',
108+
[URL]: '/test-1',
109+
[RESPONSE_TYPE]: 'json'
110110
},
111111
'3706062823': {
112-
'body': 'buzz',
113-
'headers': {},
114-
'status': 200,
115-
'statusText': 'OK',
116-
'url': '/test-2',
117-
'responseType': 'json'
112+
[BODY]: 'buzz',
113+
[HEADERS]: {},
114+
[STATUS]: 200,
115+
[STATUS_TEXT]: 'OK',
116+
[URL]: '/test-2',
117+
[RESPONSE_TYPE]: 'json'
118118
}
119119
});
120120
}));

packages/core/test/bundling/hydration/bundle.golden_symbols.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
{
3333
"name": "BLOOM_MASK"
3434
},
35+
{
36+
"name": "BODY"
37+
},
3538
{
3639
"name": "BROWSER_MODULE_PROVIDERS"
3740
},
@@ -188,6 +191,9 @@
188191
{
189192
"name": "HAS_TRANSPLANTED_VIEWS"
190193
},
194+
{
195+
"name": "HEADERS"
196+
},
191197
{
192198
"name": "HTTP_ROOT_INTERCEPTOR_FNS"
193199
},
@@ -398,6 +404,9 @@
398404
{
399405
"name": "REMOVE_STYLES_ON_COMPONENT_DESTROY"
400406
},
407+
{
408+
"name": "RESPONSE_TYPE"
409+
},
401410
{
402411
"name": "RefCountOperator"
403412
},
@@ -425,6 +434,12 @@
425434
{
426435
"name": "SKIP_HYDRATION_ATTR_NAME_LOWER_CASE"
427436
},
437+
{
438+
"name": "STATUS"
439+
},
440+
{
441+
"name": "STATUS_TEXT"
442+
},
428443
{
429444
"name": "SafeSubscriber"
430445
},
@@ -500,6 +515,9 @@
500515
{
501516
"name": "TransferState"
502517
},
518+
{
519+
"name": "URL2"
520+
},
503521
{
504522
"name": "USE_VALUE"
505523
},

0 commit comments

Comments
 (0)