Skip to content

Commit 272237a

Browse files
authored
refactor(module:core): cleanup animation frame polyfill (#9243)
The `reqAnimFrame` polyfill was originally designed for legacy browser support, but it is now unnecessary, particularly in Angular, which targets only evergreen browsers. BREAKING CHANGE: - refactoring in `ng-zorro-antd/core/polyfill`: - rename `cancelRequestAnimationFrame` to `cancelAnimationFrame` - rename `reqAnimFrame` to `requestAnimationFrame`
1 parent e56b11c commit 272237a

12 files changed

Lines changed: 37 additions & 81 deletions

components/core/polyfill/request-animation.ts

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,12 @@
33
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
44
*/
55

6-
import { NzSafeAny } from 'ng-zorro-antd/core/types';
7-
8-
const availablePrefixes = ['moz', 'ms', 'webkit'];
9-
10-
function requestAnimationFramePolyfill(): typeof requestAnimationFrame {
11-
let lastTime = 0;
12-
return function (callback: FrameRequestCallback): number {
13-
const currTime = new Date().getTime();
14-
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
15-
const id = window.setTimeout(() => {
16-
callback(currTime + timeToCall);
17-
}, timeToCall);
18-
lastTime = currTime + timeToCall;
19-
return id;
20-
};
21-
}
22-
23-
function getRequestAnimationFrame(): typeof requestAnimationFrame {
24-
if (typeof window === 'undefined') {
25-
return () => 0;
26-
}
27-
if (window.requestAnimationFrame) {
28-
// https://github.com/vuejs/vue/issues/4465
29-
return window.requestAnimationFrame.bind(window);
30-
}
31-
32-
const prefix = availablePrefixes.filter(key => `${key}RequestAnimationFrame` in window)[0];
33-
34-
return prefix ? (window as NzSafeAny)[`${prefix}RequestAnimationFrame`] : requestAnimationFramePolyfill();
35-
}
36-
37-
export function cancelRequestAnimationFrame(id: number): NzSafeAny {
38-
if (typeof window === 'undefined') {
39-
return null;
40-
}
41-
if (window.cancelAnimationFrame) {
42-
return window.cancelAnimationFrame(id);
43-
}
44-
const prefix = availablePrefixes.filter(
45-
key => `${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window
46-
)[0];
47-
48-
return prefix
49-
? (
50-
((window as NzSafeAny)[`${prefix}CancelAnimationFrame`] as typeof cancelAnimationFrame) ||
51-
((window as NzSafeAny)[`${prefix}CancelRequestAnimationFrame`] as typeof cancelRequestAnimationFrame)
52-
)
53-
// @ts-ignore
54-
.call(this, id)
55-
: clearTimeout(id);
56-
}
57-
58-
export const reqAnimFrame = getRequestAnimationFrame();
6+
// Note: This falls back to `setTimeout` if `requestAnimationFrame` is
7+
// unintentionally called on the server, but ideally, we should never attempt
8+
// to call `requestAnimationFrame` on the server — all invocations should be
9+
// wrapped with isBrowser.
10+
export const requestAnimationFrame =
11+
typeof globalThis.requestAnimationFrame === 'function' ? globalThis.requestAnimationFrame : globalThis.setTimeout;
12+
13+
export const cancelAnimationFrame =
14+
typeof globalThis.requestAnimationFrame === 'function' ? globalThis.cancelAnimationFrame : globalThis.clearTimeout;

components/core/services/scroll.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { DOCUMENT, inject, Injectable, NgZone } from '@angular/core';
77

8-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
8+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
99
import { NzSafeAny } from 'ng-zorro-antd/core/types';
1010

1111
export type EasyingFn = (t: number, b: number, c: number, d: number) => number;
@@ -122,7 +122,7 @@ export class NzScrollService {
122122
(target as HTMLElement).scrollTop = nextScrollTop;
123123
}
124124
if (time < duration) {
125-
reqAnimFrame(frameFunc);
125+
requestAnimationFrame(frameFunc);
126126
} else if (typeof callback === 'function') {
127127
// Caretaker note: the `frameFunc` is called within the `<root>` zone, but we have to re-enter
128128
// the Angular zone when calling custom callback to be backwards-compatible.
@@ -131,6 +131,6 @@ export class NzScrollService {
131131
};
132132
// Caretaker note: the `requestAnimationFrame` triggers change detection, but updating a `scrollTop` property or
133133
// calling `window.scrollTo` doesn't require Angular to run `ApplicationRef.tick()`.
134-
this.ngZone.runOutsideAngular(() => reqAnimFrame(frameFunc));
134+
this.ngZone.runOutsideAngular(() => requestAnimationFrame(frameFunc));
135135
}
136136
}

components/graph/core/minimap.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { drag } from 'd3-drag';
99
import { pointer, select } from 'd3-selection';
1010
import { ZoomBehavior, zoomIdentity, ZoomTransform } from 'd3-zoom';
1111

12-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
12+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
1313
import { NzSafeAny } from 'ng-zorro-antd/core/types';
1414

1515
import { NzZoomTransform } from '../interface';
@@ -178,7 +178,7 @@ export class Minimap {
178178
if (this.translate != null && this.zoom != null) {
179179
// Update the viewpoint rectangle shape since the aspect ratio of the
180180
// map has changed.
181-
this.ngZone.runOutsideAngular(() => reqAnimFrame(() => this.zoom()));
181+
this.ngZone.runOutsideAngular(() => requestAnimationFrame(() => this.zoom()));
182182
}
183183

184184
// Serialize the main svg to a string which will be used as the rendering
@@ -202,7 +202,7 @@ export class Minimap {
202202
context!.drawImage(image, minimapOffset.x, minimapOffset.y, this.minimapSize.width, this.minimapSize.height);
203203

204204
this.ngZone.runOutsideAngular(() => {
205-
reqAnimFrame(() => {
205+
requestAnimationFrame(() => {
206206
// Hide the old canvas and show the new buffer canvas.
207207
select(this.canvasBuffer).style('display', 'block');
208208
select(this.canvas).style('display', 'none');

components/graph/graph.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { finalize, take } from 'rxjs/operators';
3333
import { buildGraph } from 'dagre-compound';
3434

3535
import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation';
36-
import { cancelRequestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
36+
import { cancelAnimationFrame } from 'ng-zorro-antd/core/polyfill';
3737
import { NzSafeAny } from 'ng-zorro-antd/core/types';
3838

3939
import { calculateTransform } from './core/utils';
@@ -199,7 +199,7 @@ export class NzGraphComponent implements OnInit, OnChanges, AfterContentChecked,
199199
this._dataSubscription.unsubscribe();
200200
this._dataSubscription = null;
201201
}
202-
cancelRequestAnimationFrame(this.requestId);
202+
cancelAnimationFrame(this.requestId);
203203
});
204204
}
205205

components/modal/modal-container.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
2626

2727
import { NzConfigService } from 'ng-zorro-antd/core/config';
28-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
28+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
2929
import { NzSafeAny } from 'ng-zorro-antd/core/types';
3030
import { fromEventOutsideAngular, getElementOffset, isNotNil } from 'ng-zorro-antd/core/util';
3131

@@ -162,7 +162,7 @@ export class BaseModalContainerComponent extends BasePortalOutlet {
162162
if (this.document) {
163163
this.elementFocusedBeforeModalWasOpened = this.document.activeElement as HTMLElement;
164164
if (this.host.nativeElement.focus) {
165-
this.ngZone.runOutsideAngular(() => reqAnimFrame(() => this.host.nativeElement.focus()));
165+
this.ngZone.runOutsideAngular(() => requestAnimationFrame(() => this.host.nativeElement.focus()));
166166
}
167167
}
168168
}

components/select/select-search.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
} from '@angular/core';
2222
import { COMPOSITION_BUFFER_MODE, FormsModule } from '@angular/forms';
2323

24-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
24+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
2525

2626
@Component({
2727
selector: 'nz-select-search',
@@ -85,7 +85,7 @@ export class NzSelectSearchComponent implements AfterViewInit, OnChanges {
8585
}
8686

8787
syncMirrorWidth(): void {
88-
reqAnimFrame(() => {
88+
requestAnimationFrame(() => {
8989
const mirrorDOM = this.mirrorElement!.nativeElement;
9090
const hostDOM = this.elementRef.nativeElement;
9191
const inputDOM = this.inputElement.nativeElement;

components/select/select.component.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/con
5050
import { NzFormItemFeedbackIconComponent, NzFormNoStatusService, NzFormStatusService } from 'ng-zorro-antd/core/form';
5151
import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation';
5252
import { NzOverlayModule, POSITION_MAP, POSITION_TYPE, getPlacementName } from 'ng-zorro-antd/core/overlay';
53-
import { cancelRequestAnimationFrame, reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
53+
import { cancelAnimationFrame, requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
5454
import {
5555
NgClassInterface,
5656
NzSafeAny,
@@ -607,8 +607,8 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
607607
updateCdkConnectedOverlayStatus(): void {
608608
if (this.platform.isBrowser && this.originElement.nativeElement) {
609609
const triggerWidth = this.triggerWidth;
610-
cancelRequestAnimationFrame(this.requestId);
611-
this.requestId = reqAnimFrame(() => {
610+
cancelAnimationFrame(this.requestId);
611+
this.requestId = requestAnimationFrame(() => {
612612
// Blink triggers style and layout pipelines anytime the `getBoundingClientRect()` is called, which may cause a
613613
// frame drop. That's why it's scheduled through the `requestAnimationFrame` to unload the composite thread.
614614
this.triggerWidth = this.originElement.nativeElement.getBoundingClientRect().width;
@@ -623,7 +623,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
623623
}
624624

625625
updateCdkConnectedOverlayPositions(): void {
626-
reqAnimFrame(() => {
626+
requestAnimationFrame(() => {
627627
this.cdkConnectedOverlay?.overlayRef?.updatePosition();
628628
});
629629
}
@@ -634,7 +634,7 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
634634

635635
constructor() {
636636
this.destroyRef.onDestroy(() => {
637-
cancelRequestAnimationFrame(this.requestId);
637+
cancelAnimationFrame(this.requestId);
638638
this.focusMonitor.stopMonitoring(this.host);
639639
});
640640
}

components/tabs/tab-nav-bar.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { animationFrameScheduler, asapScheduler, merge, of } from 'rxjs';
3838
import { auditTime } from 'rxjs/operators';
3939

4040
import { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';
41-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
41+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
4242
import { NzSafeAny } from 'ng-zorro-antd/core/types';
4343

4444
import { NzTabPositionMode, NzTabScrollEvent, NzTabScrollListOffsetEvent } from './interfaces';
@@ -229,7 +229,7 @@ export class NzTabNavBarComponent implements AfterViewInit, AfterContentChecked,
229229
.withWrap();
230230
this.keyManager.updateActiveItem(this.selectedIndex);
231231

232-
reqAnimFrame(realign);
232+
requestAnimationFrame(realign);
233233

234234
merge(this.nzResizeObserver.observe(this.navWrapRef), this.nzResizeObserver.observe(this.navListRef))
235235
.pipe(takeUntilDestroyed(this.destroyRef), auditTime(16, RESIZE_SCHEDULER))

components/tabs/tabs-ink-bar.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { Directive, ElementRef, Input, NgZone, inject } from '@angular/core';
77
import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
88

9-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
9+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
1010

1111
import { NzTabPositionMode } from './interfaces';
1212

@@ -31,7 +31,7 @@ export class NzTabsInkBarDirective {
3131

3232
alignToElement(element: HTMLElement): void {
3333
this.ngZone.runOutsideAngular(() => {
34-
reqAnimFrame(() => this.setStyles(element));
34+
requestAnimationFrame(() => this.setStyles(element));
3535
});
3636
}
3737

components/time-picker/time-picker-panel.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3030
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
3131

3232
import { NzButtonModule } from 'ng-zorro-antd/button';
33-
import { reqAnimFrame } from 'ng-zorro-antd/core/polyfill';
33+
import { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
3434
import { fromEventOutsideAngular, isNotNil } from 'ng-zorro-antd/core/util';
3535
import { DateHelperService, NzI18nModule } from 'ng-zorro-antd/i18n';
3636

@@ -465,7 +465,7 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
465465
const perTick = (difference / duration) * 10;
466466

467467
this.ngZone.runOutsideAngular(() => {
468-
reqAnimFrame(() => {
468+
requestAnimationFrame(() => {
469469
element.scrollTop = element.scrollTop + perTick;
470470
if (element.scrollTop === to) {
471471
return;

0 commit comments

Comments
 (0)