@angular/core 17.3.1 → 18.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/application/application_ref.mjs +14 -29
- package/esm2022/src/change_detection/flags.mjs +4 -3
- package/esm2022/src/change_detection/scheduling/zoneless_scheduling_impl.mjs +6 -34
- package/esm2022/src/render3/component_ref.mjs +1 -1
- package/esm2022/src/render3/instructions/change_detection.mjs +26 -18
- package/esm2022/src/render3/instructions/mark_view_dirty.mjs +11 -2
- package/esm2022/src/render3/state.mjs +13 -1
- package/esm2022/src/util/callback_scheduler.mjs +74 -0
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/src/zone/ng_zone.mjs +9 -8
- package/esm2022/testing/src/component_fixture.mjs +46 -11
- package/esm2022/testing/src/logger.mjs +3 -3
- package/fesm2022/core.mjs +133 -113
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs +1 -1
- package/fesm2022/testing.mjs +46 -11
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +1 -1
- package/schematics/migrations/block-template-entities/bundle.js +6542 -10011
- package/schematics/migrations/block-template-entities/bundle.js.map +4 -4
- package/schematics/migrations/invalid-two-way-bindings/bundle.js +9282 -12751
- package/schematics/migrations/invalid-two-way-bindings/bundle.js.map +4 -4
- package/schematics/ng-generate/control-flow-migration/bundle.js +6553 -10022
- package/schematics/ng-generate/control-flow-migration/bundle.js.map +4 -4
- package/schematics/ng-generate/standalone-migration/bundle.js +14133 -16201
- package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
- package/testing/index.d.ts +1 -1
- package/esm2022/src/util/raf.mjs +0 -41
package/fesm2022/core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular
|
|
2
|
+
* @license Angular v18.0.0-next.1
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -4152,8 +4152,9 @@ const profiler = function (event, instance, hookOrListener) {
|
|
|
4152
4152
|
const SVG_NAMESPACE = 'svg';
|
|
4153
4153
|
const MATH_ML_NAMESPACE = 'math';
|
|
4154
4154
|
|
|
4155
|
-
// TODO(atscott):
|
|
4156
|
-
|
|
4155
|
+
// TODO(atscott): Remove prior to v18 release. Keeping this around in case anyone internally needs
|
|
4156
|
+
// to opt out temporarily.
|
|
4157
|
+
let _ensureDirtyViewsAreAlwaysReachable = true;
|
|
4157
4158
|
function getEnsureDirtyViewsAreAlwaysReachable() {
|
|
4158
4159
|
return _ensureDirtyViewsAreAlwaysReachable;
|
|
4159
4160
|
}
|
|
@@ -4415,6 +4416,12 @@ const instructionState = {
|
|
|
4415
4416
|
* changes exist in the change detector or its children.
|
|
4416
4417
|
*/
|
|
4417
4418
|
let _isInCheckNoChangesMode = false;
|
|
4419
|
+
/**
|
|
4420
|
+
* Flag used to indicate that we are in the middle running change detection on a view
|
|
4421
|
+
*
|
|
4422
|
+
* @see detectChangesInViewWhileDirty
|
|
4423
|
+
*/
|
|
4424
|
+
let _isRefreshingViews = false;
|
|
4418
4425
|
/**
|
|
4419
4426
|
* Returns true if the instruction state stack is empty.
|
|
4420
4427
|
*
|
|
@@ -4585,6 +4592,12 @@ function setIsInCheckNoChangesMode(mode) {
|
|
|
4585
4592
|
!ngDevMode && throwError('Must never be called in production mode');
|
|
4586
4593
|
_isInCheckNoChangesMode = mode;
|
|
4587
4594
|
}
|
|
4595
|
+
function isRefreshingViews() {
|
|
4596
|
+
return _isRefreshingViews;
|
|
4597
|
+
}
|
|
4598
|
+
function setIsRefreshingViews(mode) {
|
|
4599
|
+
_isRefreshingViews = mode;
|
|
4600
|
+
}
|
|
4588
4601
|
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
|
4589
4602
|
function getBindingRoot() {
|
|
4590
4603
|
const lFrame = instructionState.lFrame;
|
|
@@ -12654,7 +12667,7 @@ const REACTIVE_LVIEW_CONSUMER_NODE = {
|
|
|
12654
12667
|
/**
|
|
12655
12668
|
* The maximum number of times the change detection traversal will rerun before throwing an error.
|
|
12656
12669
|
*/
|
|
12657
|
-
const MAXIMUM_REFRESH_RERUNS = 100;
|
|
12670
|
+
const MAXIMUM_REFRESH_RERUNS$1 = 100;
|
|
12658
12671
|
function detectChangesInternal(lView, notifyErrorHandler = true, mode = 0 /* ChangeDetectionMode.Global */) {
|
|
12659
12672
|
const environment = lView[ENVIRONMENT];
|
|
12660
12673
|
const rendererFactory = environment.rendererFactory;
|
|
@@ -12684,23 +12697,31 @@ function detectChangesInternal(lView, notifyErrorHandler = true, mode = 0 /* Cha
|
|
|
12684
12697
|
}
|
|
12685
12698
|
}
|
|
12686
12699
|
function detectChangesInViewWhileDirty(lView, mode) {
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12700
|
+
const lastIsRefreshingViewsValue = isRefreshingViews();
|
|
12701
|
+
try {
|
|
12702
|
+
setIsRefreshingViews(true);
|
|
12703
|
+
detectChangesInView$1(lView, mode);
|
|
12704
|
+
let retries = 0;
|
|
12705
|
+
// If after running change detection, this view still needs to be refreshed or there are
|
|
12706
|
+
// descendants views that need to be refreshed due to re-dirtying during the change detection
|
|
12707
|
+
// run, detect changes on the view again. We run change detection in `Targeted` mode to only
|
|
12708
|
+
// refresh views with the `RefreshView` flag.
|
|
12709
|
+
while (requiresRefreshOrTraversal(lView)) {
|
|
12710
|
+
if (retries === MAXIMUM_REFRESH_RERUNS$1) {
|
|
12711
|
+
throw new RuntimeError(103 /* RuntimeErrorCode.INFINITE_CHANGE_DETECTION */, ngDevMode &&
|
|
12712
|
+
'Infinite change detection while trying to refresh views. ' +
|
|
12713
|
+
'There may be components which each cause the other to require a refresh, ' +
|
|
12714
|
+
'causing an infinite loop.');
|
|
12715
|
+
}
|
|
12716
|
+
retries++;
|
|
12717
|
+
// Even if this view is detached, we still detect changes in targeted mode because this was
|
|
12718
|
+
// the root of the change detection run.
|
|
12719
|
+
detectChangesInView$1(lView, 1 /* ChangeDetectionMode.Targeted */);
|
|
12699
12720
|
}
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
//
|
|
12703
|
-
|
|
12721
|
+
}
|
|
12722
|
+
finally {
|
|
12723
|
+
// restore state to what it was before entering this change detection loop
|
|
12724
|
+
setIsRefreshingViews(lastIsRefreshingViewsValue);
|
|
12704
12725
|
}
|
|
12705
12726
|
}
|
|
12706
12727
|
function checkNoChangesInternal(lView, notifyErrorHandler = true) {
|
|
@@ -12996,9 +13017,17 @@ function detectChangesInChildComponents(hostLView, components, mode) {
|
|
|
12996
13017
|
* @returns the root LView
|
|
12997
13018
|
*/
|
|
12998
13019
|
function markViewDirty(lView) {
|
|
13020
|
+
const dirtyBitsToUse = isRefreshingViews() ?
|
|
13021
|
+
64 /* LViewFlags.Dirty */ :
|
|
13022
|
+
// When we are not actively refreshing a view tree, it is absolutely
|
|
13023
|
+
// valid to update state and mark views dirty. We use the `RefreshView` flag in this
|
|
13024
|
+
// case to allow synchronously rerunning change detection. This applies today to
|
|
13025
|
+
// afterRender hooks as well as animation listeners which execute after detecting
|
|
13026
|
+
// changes in a view when the render factory flushes.
|
|
13027
|
+
1024 /* LViewFlags.RefreshView */ | 64 /* LViewFlags.Dirty */;
|
|
12999
13028
|
lView[ENVIRONMENT].changeDetectionScheduler?.notify();
|
|
13000
13029
|
while (lView) {
|
|
13001
|
-
lView[FLAGS] |=
|
|
13030
|
+
lView[FLAGS] |= dirtyBitsToUse;
|
|
13002
13031
|
const parent = getLViewParent(lView);
|
|
13003
13032
|
// Stop traversing up as soon as you find a root view that wasn't attached to any container
|
|
13004
13033
|
if (isRootView(lView) && !parent) {
|
|
@@ -14459,41 +14488,74 @@ function performanceMarkFeature(feature) {
|
|
|
14459
14488
|
performance?.mark?.('mark_feature_usage', { detail: { feature } });
|
|
14460
14489
|
}
|
|
14461
14490
|
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
|
|
14465
|
-
|
|
14466
|
-
|
|
14491
|
+
/**
|
|
14492
|
+
* Gets a scheduling function that runs the callback after the first of setTimeout and
|
|
14493
|
+
* requestAnimationFrame resolves.
|
|
14494
|
+
*
|
|
14495
|
+
* - `requestAnimationFrame` ensures that change detection runs ahead of a browser repaint.
|
|
14496
|
+
* This ensures that the create and update passes of a change detection always happen
|
|
14497
|
+
* in the same frame.
|
|
14498
|
+
* - When the browser is resource-starved, `rAF` can execute _before_ a `setTimeout` because
|
|
14499
|
+
* rendering is a very high priority process. This means that `setTimeout` cannot guarantee
|
|
14500
|
+
* same-frame create and update pass, when `setTimeout` is used to schedule the update phase.
|
|
14501
|
+
* - While `rAF` gives us the desirable same-frame updates, it has two limitations that
|
|
14502
|
+
* prevent it from being used alone. First, it does not run in background tabs, which would
|
|
14503
|
+
* prevent Angular from initializing an application when opened in a new tab (for example).
|
|
14504
|
+
* Second, repeated calls to requestAnimationFrame will execute at the refresh rate of the
|
|
14505
|
+
* hardware (~16ms for a 60Hz display). This would cause significant slowdown of tests that
|
|
14506
|
+
* are written with several updates and asserts in the form of "update; await stable; assert;".
|
|
14507
|
+
* - Both `setTimeout` and `rAF` are able to "coalesce" several events from a single user
|
|
14508
|
+
* interaction into a single change detection. Importantly, this reduces view tree traversals when
|
|
14509
|
+
* compared to an alternative timing mechanism like `queueMicrotask`, where change detection would
|
|
14510
|
+
* then be interleaves between each event.
|
|
14511
|
+
*
|
|
14512
|
+
* By running change detection after the first of `setTimeout` and `rAF` to execute, we get the
|
|
14513
|
+
* best of both worlds.
|
|
14514
|
+
*/
|
|
14515
|
+
function getCallbackScheduler() {
|
|
14467
14516
|
// Note: the `getNativeRequestAnimationFrame` is used in the `NgZone` class, but we cannot use the
|
|
14468
14517
|
// `inject` function. The `NgZone` instance may be created manually, and thus the injection
|
|
14469
14518
|
// context will be unavailable. This might be enough to check whether `requestAnimationFrame` is
|
|
14470
14519
|
// available because otherwise, we'll fall back to `setTimeout`.
|
|
14471
|
-
const
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
// `requestAnimationFrame` is used in the browser to coalesce event tasks since event tasks are
|
|
14476
|
-
// usually executed within the same rendering frame (but this is more implementation details of
|
|
14477
|
-
// browsers).
|
|
14478
|
-
let nativeRequestAnimationFrame = _global[isBrowser ? 'requestAnimationFrame' : 'setTimeout'];
|
|
14479
|
-
let nativeCancelAnimationFrame = _global[isBrowser ? 'cancelAnimationFrame' : 'clearTimeout'];
|
|
14480
|
-
if (typeof Zone !== 'undefined' && nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
|
|
14520
|
+
const hasRequestAnimationFrame = typeof _global['requestAnimationFrame'] === 'function';
|
|
14521
|
+
let nativeRequestAnimationFrame = hasRequestAnimationFrame ? _global['requestAnimationFrame'] : null;
|
|
14522
|
+
let nativeSetTimeout = _global['setTimeout'];
|
|
14523
|
+
if (typeof Zone !== 'undefined') {
|
|
14481
14524
|
// Note: zone.js sets original implementations on patched APIs behind the
|
|
14482
14525
|
// `__zone_symbol__OriginalDelegate` key (see `attachOriginToPatched`). Given the following
|
|
14483
14526
|
// example: `window.requestAnimationFrame.__zone_symbol__OriginalDelegate`; this would return an
|
|
14484
14527
|
// unpatched implementation of the `requestAnimationFrame`, which isn't intercepted by the
|
|
14485
14528
|
// Angular zone. We use the unpatched implementation to avoid another change detection when
|
|
14486
14529
|
// coalescing tasks.
|
|
14487
|
-
const
|
|
14488
|
-
if (
|
|
14489
|
-
nativeRequestAnimationFrame =
|
|
14490
|
-
|
|
14491
|
-
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14530
|
+
const ORIGINAL_DELEGATE_SYMBOL = Zone.__symbol__('OriginalDelegate');
|
|
14531
|
+
if (nativeRequestAnimationFrame) {
|
|
14532
|
+
nativeRequestAnimationFrame =
|
|
14533
|
+
nativeRequestAnimationFrame[ORIGINAL_DELEGATE_SYMBOL] ??
|
|
14534
|
+
nativeRequestAnimationFrame;
|
|
14535
|
+
}
|
|
14536
|
+
nativeSetTimeout = nativeSetTimeout[ORIGINAL_DELEGATE_SYMBOL] ?? nativeSetTimeout;
|
|
14537
|
+
}
|
|
14538
|
+
return (callback) => {
|
|
14539
|
+
let executeCallback = true;
|
|
14540
|
+
nativeSetTimeout(() => {
|
|
14541
|
+
if (!executeCallback) {
|
|
14542
|
+
return;
|
|
14543
|
+
}
|
|
14544
|
+
executeCallback = false;
|
|
14545
|
+
callback();
|
|
14546
|
+
});
|
|
14547
|
+
nativeRequestAnimationFrame?.(() => {
|
|
14548
|
+
if (!executeCallback) {
|
|
14549
|
+
return;
|
|
14550
|
+
}
|
|
14551
|
+
executeCallback = false;
|
|
14552
|
+
callback();
|
|
14553
|
+
});
|
|
14554
|
+
};
|
|
14555
|
+
}
|
|
14556
|
+
|
|
14557
|
+
function noop(...args) {
|
|
14558
|
+
// Do nothing.
|
|
14497
14559
|
}
|
|
14498
14560
|
|
|
14499
14561
|
class AsyncStackTaggingZoneSpec {
|
|
@@ -14645,8 +14707,8 @@ class NgZone {
|
|
|
14645
14707
|
self.shouldCoalesceEventChangeDetection =
|
|
14646
14708
|
!shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
|
|
14647
14709
|
self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
|
|
14648
|
-
self.
|
|
14649
|
-
self.
|
|
14710
|
+
self.callbackScheduled = false;
|
|
14711
|
+
self.scheduleCallback = getCallbackScheduler();
|
|
14650
14712
|
forkInnerZoneWithAngularBehavior(self);
|
|
14651
14713
|
}
|
|
14652
14714
|
/**
|
|
@@ -14782,10 +14844,11 @@ function delayChangeDetectionForEvents(zone) {
|
|
|
14782
14844
|
* so we also need to check the _nesting here to prevent multiple
|
|
14783
14845
|
* change detections.
|
|
14784
14846
|
*/
|
|
14785
|
-
if (zone.isCheckStableRunning || zone.
|
|
14847
|
+
if (zone.isCheckStableRunning || zone.callbackScheduled) {
|
|
14786
14848
|
return;
|
|
14787
14849
|
}
|
|
14788
|
-
zone.
|
|
14850
|
+
zone.callbackScheduled = true;
|
|
14851
|
+
zone.scheduleCallback.call(_global, () => {
|
|
14789
14852
|
// This is a work around for https://github.com/angular/angular/issues/36839.
|
|
14790
14853
|
// The core issue is that when event coalescing is enabled it is possible for microtasks
|
|
14791
14854
|
// to get flushed too early (As is the case with `Promise.then`) between the
|
|
@@ -14797,7 +14860,7 @@ function delayChangeDetectionForEvents(zone) {
|
|
|
14797
14860
|
// eventTask execution.
|
|
14798
14861
|
if (!zone.fakeTopEventTask) {
|
|
14799
14862
|
zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
|
|
14800
|
-
zone.
|
|
14863
|
+
zone.callbackScheduled = false;
|
|
14801
14864
|
updateMicroTaskStatus(zone);
|
|
14802
14865
|
zone.isCheckStableRunning = true;
|
|
14803
14866
|
checkStable(zone);
|
|
@@ -14868,7 +14931,7 @@ function forkInnerZoneWithAngularBehavior(zone) {
|
|
|
14868
14931
|
function updateMicroTaskStatus(zone) {
|
|
14869
14932
|
if (zone._hasPendingMicrotasks ||
|
|
14870
14933
|
((zone.shouldCoalesceEventChangeDetection || zone.shouldCoalesceRunChangeDetection) &&
|
|
14871
|
-
zone.
|
|
14934
|
+
zone.callbackScheduled === true)) {
|
|
14872
14935
|
zone.hasPendingMicrotasks = true;
|
|
14873
14936
|
}
|
|
14874
14937
|
else {
|
|
@@ -15977,7 +16040,7 @@ function createRootComponent(componentView, rootComponentDef, rootDirectives, ho
|
|
|
15977
16040
|
function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
|
|
15978
16041
|
if (rootSelectorOrNode) {
|
|
15979
16042
|
// The placeholder will be replaced with the actual version at build time.
|
|
15980
|
-
setUpAttributes(hostRenderer, hostRNode, ['ng-version', '
|
|
16043
|
+
setUpAttributes(hostRenderer, hostRNode, ['ng-version', '18.0.0-next.1']);
|
|
15981
16044
|
}
|
|
15982
16045
|
else {
|
|
15983
16046
|
// If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
|
|
@@ -29741,7 +29804,7 @@ class Version {
|
|
|
29741
29804
|
/**
|
|
29742
29805
|
* @publicApi
|
|
29743
29806
|
*/
|
|
29744
|
-
const VERSION = new Version('
|
|
29807
|
+
const VERSION = new Version('18.0.0-next.1');
|
|
29745
29808
|
|
|
29746
29809
|
class Console {
|
|
29747
29810
|
log(message) {
|
|
@@ -31144,6 +31207,8 @@ class NgProbeToken {
|
|
|
31144
31207
|
this.token = token;
|
|
31145
31208
|
}
|
|
31146
31209
|
}
|
|
31210
|
+
/** Maximum number of times ApplicationRef will refresh all attached views in a single tick. */
|
|
31211
|
+
const MAXIMUM_REFRESH_RERUNS = 10;
|
|
31147
31212
|
function _callAndReportToErrorHandler(errorHandler, ngZone, callback) {
|
|
31148
31213
|
try {
|
|
31149
31214
|
const result = callback();
|
|
@@ -31423,12 +31488,7 @@ class ApplicationRef {
|
|
|
31423
31488
|
detectChangesInAttachedViews(refreshViews) {
|
|
31424
31489
|
let runs = 0;
|
|
31425
31490
|
const afterRenderEffectManager = this.afterRenderEffectManager;
|
|
31426
|
-
while (
|
|
31427
|
-
if (runs === MAXIMUM_REFRESH_RERUNS) {
|
|
31428
|
-
throw new RuntimeError(103 /* RuntimeErrorCode.INFINITE_CHANGE_DETECTION */, ngDevMode &&
|
|
31429
|
-
'Infinite change detection while refreshing application views. ' +
|
|
31430
|
-
'Ensure afterRender or queueStateUpdate hooks are not continuously causing updates.');
|
|
31431
|
-
}
|
|
31491
|
+
while (runs < MAXIMUM_REFRESH_RERUNS) {
|
|
31432
31492
|
if (refreshViews) {
|
|
31433
31493
|
const isFirstPass = runs === 0;
|
|
31434
31494
|
this.beforeRender.next(isFirstPass);
|
|
@@ -31450,6 +31510,12 @@ class ApplicationRef {
|
|
|
31450
31510
|
break;
|
|
31451
31511
|
}
|
|
31452
31512
|
}
|
|
31513
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) && runs >= MAXIMUM_REFRESH_RERUNS) {
|
|
31514
|
+
throw new RuntimeError(103 /* RuntimeErrorCode.INFINITE_CHANGE_DETECTION */, ngDevMode &&
|
|
31515
|
+
'Infinite change detection while refreshing application views. ' +
|
|
31516
|
+
'Ensure views are not calling `markForCheck` on every template execution or ' +
|
|
31517
|
+
'that afterRender hooks always mark views for check.');
|
|
31518
|
+
}
|
|
31453
31519
|
}
|
|
31454
31520
|
/**
|
|
31455
31521
|
* Attaches a view so that it will be dirty checked.
|
|
@@ -31584,27 +31650,9 @@ function shouldRecheckView(view) {
|
|
|
31584
31650
|
return requiresRefreshOrTraversal(view);
|
|
31585
31651
|
}
|
|
31586
31652
|
function detectChangesInView(lView, notifyErrorHandler, isFirstPass) {
|
|
31587
|
-
|
|
31588
|
-
|
|
31589
|
-
|
|
31590
|
-
mode = 0 /* ChangeDetectionMode.Global */;
|
|
31591
|
-
// Add `RefreshView` flag to ensure this view is refreshed if not already dirty.
|
|
31592
|
-
// `RefreshView` flag is used intentionally over `Dirty` because it gets cleared before
|
|
31593
|
-
// executing any of the actual refresh code while the `Dirty` flag doesn't get cleared
|
|
31594
|
-
// until the end of the refresh. Using `RefreshView` prevents creating a potential
|
|
31595
|
-
// difference in the state of the LViewFlags during template execution.
|
|
31596
|
-
lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
|
|
31597
|
-
}
|
|
31598
|
-
else if (lView[FLAGS] & 64 /* LViewFlags.Dirty */) {
|
|
31599
|
-
// The root view has been explicitly marked for check, so check it in Global mode.
|
|
31600
|
-
mode = 0 /* ChangeDetectionMode.Global */;
|
|
31601
|
-
}
|
|
31602
|
-
else {
|
|
31603
|
-
// The view has not been marked for check, but contains a view marked for refresh
|
|
31604
|
-
// (likely via a signal). Start this change detection in Targeted mode to skip the root
|
|
31605
|
-
// view and check just the view(s) that need refreshed.
|
|
31606
|
-
mode = 1 /* ChangeDetectionMode.Targeted */;
|
|
31607
|
-
}
|
|
31653
|
+
const mode = isFirstPass || lView[FLAGS] & 64 /* LViewFlags.Dirty */ ?
|
|
31654
|
+
0 /* ChangeDetectionMode.Global */ :
|
|
31655
|
+
1 /* ChangeDetectionMode.Targeted */;
|
|
31608
31656
|
detectChangesInternal(lView, notifyErrorHandler, mode);
|
|
31609
31657
|
}
|
|
31610
31658
|
|
|
@@ -35001,6 +35049,7 @@ class ChangeDetectionSchedulerImpl {
|
|
|
35001
35049
|
this.taskService = inject(PendingTasks);
|
|
35002
35050
|
this.pendingRenderTaskId = null;
|
|
35003
35051
|
this.shouldRefreshViews = false;
|
|
35052
|
+
this.schedule = getCallbackScheduler();
|
|
35004
35053
|
}
|
|
35005
35054
|
notify(type = 0 /* NotificationType.RefreshViews */) {
|
|
35006
35055
|
// When the only source of notification is an afterRender hook will skip straight to the hooks
|
|
@@ -35010,38 +35059,9 @@ class ChangeDetectionSchedulerImpl {
|
|
|
35010
35059
|
return;
|
|
35011
35060
|
}
|
|
35012
35061
|
this.pendingRenderTaskId = this.taskService.add();
|
|
35013
|
-
this.
|
|
35014
|
-
|
|
35015
|
-
|
|
35016
|
-
* Run change detection after the first of setTimeout and requestAnimationFrame resolves.
|
|
35017
|
-
*
|
|
35018
|
-
* - `requestAnimationFrame` ensures that change detection runs ahead of a browser repaint.
|
|
35019
|
-
* This ensures that the create and update passes of a change detection always happen
|
|
35020
|
-
* in the same frame.
|
|
35021
|
-
* - When the browser is resource-starved, `rAF` can execute _before_ a `setTimeout` because
|
|
35022
|
-
* rendering is a very high priority process. This means that `setTimeout` cannot guarantee
|
|
35023
|
-
* same-frame create and update pass, when `setTimeout` is used to schedule the update phase.
|
|
35024
|
-
* - While `rAF` gives us the desirable same-frame updates, it has two limitations that
|
|
35025
|
-
* prevent it from being used alone. First, it does not run in background tabs, which would
|
|
35026
|
-
* prevent Angular from initializing an application when opened in a new tab (for example).
|
|
35027
|
-
* Second, repeated calls to requestAnimationFrame will execute at the refresh rate of the
|
|
35028
|
-
* hardware (~16ms for a 60Hz display). This would cause significant slowdown of tests that
|
|
35029
|
-
* are written with several updates and asserts in the form of "update; await stable; assert;".
|
|
35030
|
-
* - Both `setTimeout` and `rAF` are able to "coalesce" several events from a single user
|
|
35031
|
-
* interaction into a single change detection. Importantly, this reduces view tree traversals when
|
|
35032
|
-
* compared to an alternative timing mechanism like `queueMicrotask`, where change detection would
|
|
35033
|
-
* then be interleaves between each event.
|
|
35034
|
-
*
|
|
35035
|
-
* By running change detection after the first of `setTimeout` and `rAF` to execute, we get the
|
|
35036
|
-
* best of both worlds.
|
|
35037
|
-
*/
|
|
35038
|
-
async raceTimeoutAndRequestAnimationFrame() {
|
|
35039
|
-
const timeout = new Promise(resolve => setTimeout(resolve));
|
|
35040
|
-
const rAF = typeof _global['requestAnimationFrame'] === 'function' ?
|
|
35041
|
-
new Promise(resolve => requestAnimationFrame(() => resolve())) :
|
|
35042
|
-
null;
|
|
35043
|
-
await Promise.race([timeout, rAF]);
|
|
35044
|
-
this.tick();
|
|
35062
|
+
this.schedule(() => {
|
|
35063
|
+
this.tick();
|
|
35064
|
+
});
|
|
35045
35065
|
}
|
|
35046
35066
|
tick() {
|
|
35047
35067
|
try {
|