fix(ivy): support env where requestAnimationFrame is not available (#26779)

PR Close #26779
This commit is contained in:
Marc Laval 2018-10-26 12:27:40 +02:00 committed by Kara Erickson
parent dc2464eaaa
commit 297c54ebb3
9 changed files with 60 additions and 21 deletions

View File

@ -21,11 +21,11 @@ import {CLEAN_PROMISE, createLViewData, createNodeAtIndex, createTView, getOrCre
import {ComponentDef, ComponentType} from './interfaces/definition'; import {ComponentDef, ComponentType} from './interfaces/definition';
import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node'; import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
import {PlayerHandler} from './interfaces/player'; import {PlayerHandler} from './interfaces/player';
import {RElement, RNode, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
import {publishDefaultGlobalUtils} from './publish_global_util'; import {publishDefaultGlobalUtils} from './publish_global_util';
import {enterView, leaveView, resetComponentState} from './state'; import {enterView, leaveView, resetComponentState} from './state';
import {getRootView, readElementValue, readPatchedLViewData, stringify} from './util'; import {defaultScheduler, getRootView, readElementValue, readPatchedLViewData, stringify} from './util';
/** Options that control how the component should be bootstrapped. */ /** Options that control how the component should be bootstrapped. */
@ -117,8 +117,7 @@ export function renderComponent<T>(
const hostRNode = locateHostElement(rendererFactory, opts.host || componentTag); const hostRNode = locateHostElement(rendererFactory, opts.host || componentTag);
const rootFlags = componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot : const rootFlags = componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot :
LViewFlags.CheckAlways | LViewFlags.IsRoot; LViewFlags.CheckAlways | LViewFlags.IsRoot;
const rootContext = createRootContext( const rootContext = createRootContext(opts.scheduler, opts.playerHandler);
opts.scheduler || requestAnimationFrame.bind(window), opts.playerHandler || null);
const renderer = rendererFactory.createRenderer(hostRNode, componentDef); const renderer = rendererFactory.createRenderer(hostRNode, componentDef);
const rootView: LViewData = createLViewData( const rootView: LViewData = createLViewData(
@ -132,7 +131,7 @@ export function renderComponent<T>(
const componentView = const componentView =
createRootComponentView(hostRNode, componentDef, rootView, renderer, sanitizer); createRootComponentView(hostRNode, componentDef, rootView, renderer, sanitizer);
component = createRootComponent( component = createRootComponent(
hostRNode, componentView, componentDef, rootView, rootContext, opts.hostFeatures || null); componentView, componentDef, rootView, rootContext, opts.hostFeatures || null);
refreshDescendantViews(rootView, null); refreshDescendantViews(rootView, null);
} finally { } finally {
@ -184,8 +183,8 @@ export function createRootComponentView(
* renderComponent() and ViewContainerRef.createComponent(). * renderComponent() and ViewContainerRef.createComponent().
*/ */
export function createRootComponent<T>( export function createRootComponent<T>(
hostRNode: RNode | null, componentView: LViewData, componentDef: ComponentDef<T>, componentView: LViewData, componentDef: ComponentDef<T>, rootView: LViewData,
rootView: LViewData, rootContext: RootContext, hostFeatures: HostFeature[] | null): any { rootContext: RootContext, hostFeatures: HostFeature[] | null): any {
const tView = rootView[TVIEW]; const tView = rootView[TVIEW];
// Create directive instance with factory() and store at next index in viewData // Create directive instance with factory() and store at next index in viewData
const component = instantiateRootComponent(tView, rootView, componentDef); const component = instantiateRootComponent(tView, rootView, componentDef);
@ -201,10 +200,10 @@ export function createRootComponent<T>(
export function createRootContext( export function createRootContext(
scheduler: (workFn: () => void) => void, playerHandler?: PlayerHandler|null): RootContext { scheduler?: (workFn: () => void) => void, playerHandler?: PlayerHandler|null): RootContext {
return { return {
components: [], components: [],
scheduler: scheduler, scheduler: scheduler || defaultScheduler,
clean: CLEAN_PROMISE, clean: CLEAN_PROMISE,
playerHandler: playerHandler || null, playerHandler: playerHandler || null,
flags: RootContextFlags.Empty flags: RootContextFlags.Empty

View File

@ -26,7 +26,7 @@ import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {FLAGS, HEADER_OFFSET, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {FLAGS, HEADER_OFFSET, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {enterView, leaveView} from './state'; import {enterView, leaveView} from './state';
import {getTNode} from './util'; import {defaultScheduler, getTNode} from './util';
import {createElementRef} from './view_engine_compatibility'; import {createElementRef} from './view_engine_compatibility';
import {RootViewRef, ViewRef} from './view_ref'; import {RootViewRef, ViewRef} from './view_ref';
@ -62,10 +62,7 @@ export const ROOT_CONTEXT = new InjectionToken<RootContext>(
*/ */
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDULER_TOKEN', { export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDULER_TOKEN', {
providedIn: 'root', providedIn: 'root',
factory: () => { factory: () => defaultScheduler,
const useRaf = typeof requestAnimationFrame !== 'undefined' && typeof window !== 'undefined';
return useRaf ? requestAnimationFrame.bind(window) : setTimeout;
},
}); });
/** /**
@ -118,9 +115,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
const rootFlags = this.componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot : const rootFlags = this.componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot :
LViewFlags.CheckAlways | LViewFlags.IsRoot; LViewFlags.CheckAlways | LViewFlags.IsRoot;
const rootContext: RootContext = ngModule && !isInternalRootView ? const rootContext: RootContext =
ngModule.injector.get(ROOT_CONTEXT) : ngModule && !isInternalRootView ? ngModule.injector.get(ROOT_CONTEXT) : createRootContext();
createRootContext(requestAnimationFrame.bind(window));
const renderer = rendererFactory.createRenderer(hostRNode, this.componentDef); const renderer = rendererFactory.createRenderer(hostRNode, this.componentDef);
// Create the root view. Uses empty TView and ContentTemplate. // Create the root view. Uses empty TView and ContentTemplate.
@ -174,8 +170,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
// executed here? // executed here?
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
component = createRootComponent( component = createRootComponent(
hostRNode, componentView, this.componentDef, rootView, rootContext, componentView, this.componentDef, rootView, rootContext, [LifecycleHooksFeature]);
[LifecycleHooksFeature]);
refreshDescendantViews(rootView, RenderFlags.Create); refreshDescendantViews(rootView, RenderFlags.Create);
} finally { } finally {

View File

@ -358,7 +358,7 @@ export function renderEmbeddedTemplate<T>(
let oldView: LViewData; let oldView: LViewData;
if (viewToRender[FLAGS] & LViewFlags.IsRoot) { if (viewToRender[FLAGS] & LViewFlags.IsRoot) {
// This is a root view inside the view tree // This is a root view inside the view tree
tickRootContext(viewToRender[CONTEXT] as RootContext); tickRootContext(getRootContext(viewToRender));
} else { } else {
try { try {
setIsParent(true); setIsParent(true);

View File

@ -7,6 +7,7 @@
*/ */
import {devModeEqual} from '../change_detection/change_detection_util'; import {devModeEqual} from '../change_detection/change_detection_util';
import {global} from '../util';
import {assertDefined, assertLessThan} from './assert'; import {assertDefined, assertLessThan} from './assert';
import {ACTIVE_INDEX, LContainer} from './interfaces/container'; import {ACTIVE_INDEX, LContainer} from './interfaces/container';
@ -154,7 +155,10 @@ export function getRootView(target: LViewData | {}): LViewData {
} }
export function getRootContext(viewOrComponent: LViewData | {}): RootContext { export function getRootContext(viewOrComponent: LViewData | {}): RootContext {
return getRootView(viewOrComponent)[CONTEXT] as RootContext; const rootView = getRootView(viewOrComponent);
ngDevMode &&
assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?');
return rootView[CONTEXT] as RootContext;
} }
/** /**
@ -241,3 +245,8 @@ export function getParentInjectorTNode(
} }
return parentTNode; return parentTNode;
} }
export const defaultScheduler =
(typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame || // browser only
setTimeout // everything else
).bind(global);

View File

@ -434,6 +434,9 @@
{ {
"name": "decreaseElementDepthCount" "name": "decreaseElementDepthCount"
}, },
{
"name": "defaultScheduler"
},
{ {
"name": "defineComponent" "name": "defineComponent"
}, },

View File

@ -119,6 +119,15 @@
{ {
"name": "ViewEncapsulation" "name": "ViewEncapsulation"
}, },
{
"name": "__self"
},
{
"name": "__window"
},
{
"name": "_global"
},
{ {
"name": "_renderCompCount" "name": "_renderCompCount"
}, },
@ -182,6 +191,9 @@
{ {
"name": "createViewQuery" "name": "createViewQuery"
}, },
{
"name": "defaultScheduler"
},
{ {
"name": "defineComponent" "name": "defineComponent"
}, },
@ -305,6 +317,12 @@
{ {
"name": "getRendererFactory" "name": "getRendererFactory"
}, },
{
"name": "getRootContext"
},
{
"name": "getRootView"
},
{ {
"name": "getTView" "name": "getTView"
}, },

View File

@ -680,6 +680,9 @@
{ {
"name": "defaultErrorLogger" "name": "defaultErrorLogger"
}, },
{
"name": "defaultScheduler"
},
{ {
"name": "defineComponent" "name": "defineComponent"
}, },
@ -929,6 +932,12 @@
{ {
"name": "getRendererFactory" "name": "getRendererFactory"
}, },
{
"name": "getRootContext"
},
{
"name": "getRootView"
},
{ {
"name": "getSymbolIterator$1" "name": "getSymbolIterator$1"
}, },

View File

@ -491,6 +491,9 @@
{ {
"name": "decreaseElementDepthCount" "name": "decreaseElementDepthCount"
}, },
{
"name": "defaultScheduler"
},
{ {
"name": "defineComponent" "name": "defineComponent"
}, },

View File

@ -1415,6 +1415,9 @@
{ {
"name": "defaultKeyValueDiffers" "name": "defaultKeyValueDiffers"
}, },
{
"name": "defaultScheduler"
},
{ {
"name": "defineComponent" "name": "defineComponent"
}, },