perf(nav): minor performance improvements

This commit is contained in:
Manu Mtz.-Almeida
2016-11-28 01:34:19 +01:00
parent ecb8bee398
commit 4aa1ada7d5

View File

@ -216,6 +216,7 @@ export class NavControllerBase extends Ion implements NavController {
reject && reject(false, false, rejectReason); reject && reject(false, false, rejectReason);
// let's see if there's another to kick off
this.setTransitioning(false); this.setTransitioning(false);
this._sbCheck(); this._sbCheck();
this._nextTrns(); this._nextTrns();
@ -226,12 +227,12 @@ export class NavControllerBase extends Ion implements NavController {
ti.insertViews = ti.insertViews.filter(v => v !== null); ti.insertViews = ti.insertViews.filter(v => v !== null);
if (ti.insertViews.length === 0) { if (ti.insertViews.length === 0) {
ti.reject('invalid views to insert'); ti.reject('invalid views to insert');
return; return promise;
} }
} else if (isPresent(ti.removeStart) && !this._views.length && !this._isPortal) { } else if (isPresent(ti.removeStart) && this._views.length === 0 && !this._isPortal) {
ti.reject('no views in the stack to be removed'); ti.reject('no views in the stack to be removed');
return; return promise;
} }
this._queue.push(ti); this._queue.push(ti);
@ -275,15 +276,14 @@ export class NavControllerBase extends Ion implements NavController {
} }
// Only test canLeave/canEnter if there is transition // Only test canLeave/canEnter if there is transition
let requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView; const requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView;
if (requiresTransition) { if (requiresTransition) {
// views have been initialized, now let's test // views have been initialized, now let's test
// to see if the transition is even allowed or not // to see if the transition is even allowed or not
return this._viewTest(enteringView, leavingView, ti); return this._viewTest(enteringView, leavingView, ti);
} else { } else {
this._postViewInit(enteringView, leavingView, ti, ti.resolve); return this._postViewInit(enteringView, leavingView, ti);
return true;
} }
} }
@ -335,10 +335,12 @@ export class NavControllerBase extends Ion implements NavController {
const removeStart = ti.removeStart; const removeStart = ti.removeStart;
if (isPresent(removeStart)) { if (isPresent(removeStart)) {
let views = this._views; const views = this._views;
const removeEnd = removeStart + ti.removeCount; const removeEnd = removeStart + ti.removeCount;
for (var i = views.length - 1; i >= 0; i--) { let i: number;
var view = views[i]; let view: ViewController;
for (i = views.length - 1; i >= 0; i--) {
view = views[i];
if ((i < removeStart || i >= removeEnd) && view !== leavingView) { if ((i < removeStart || i >= removeEnd) && view !== leavingView) {
return view; return view;
} }
@ -347,11 +349,15 @@ export class NavControllerBase extends Ion implements NavController {
return null; return null;
} }
_postViewInit(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction, resolve: TransitionResolveFn) { _postViewInit(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) {
assert(leavingView || enteringView, 'Both leavingView and enteringView are null'); assert(leavingView || enteringView, 'Both leavingView and enteringView are null');
assert(ti.resolve, 'resolve must be valid');
assert(ti.reject, 'reject must be valid');
const opts = ti.opts || {}; const opts = ti.opts || {};
const insertViews = ti.insertViews; const insertViews = ti.insertViews;
const removeStart = ti.removeStart; const removeStart = ti.removeStart;
const removeCount = ti.removeCount;
let view: ViewController; let view: ViewController;
let i: number; let i: number;
let destroyQueue: ViewController[]; let destroyQueue: ViewController[];
@ -359,10 +365,10 @@ export class NavControllerBase extends Ion implements NavController {
// there are views to remove // there are views to remove
if (isPresent(removeStart)) { if (isPresent(removeStart)) {
assert(removeStart >= 0, 'removeStart can not be negative'); assert(removeStart >= 0, 'removeStart can not be negative');
assert(ti.removeCount >= 0, 'removeCount can not be negative'); assert(removeCount >= 0, 'removeCount can not be negative');
destroyQueue = []; destroyQueue = [];
for (i = 0; i < ti.removeCount; i++) { for (i = 0; i < removeCount; i++) {
view = this._views[i + removeStart]; view = this._views[i + removeStart];
if (view && view !== enteringView && view !== leavingView) { if (view && view !== enteringView && view !== leavingView) {
destroyQueue.push(view); destroyQueue.push(view);
@ -378,7 +384,7 @@ export class NavControllerBase extends Ion implements NavController {
console.warn(`You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.`, console.warn(`You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.`,
this, this.getNativeElement()); this, this.getNativeElement());
ti.reject && ti.reject('navigation stack needs at least one root page'); ti.reject('navigation stack needs at least one root page');
return false; return false;
} }
@ -392,6 +398,7 @@ export class NavControllerBase extends Ion implements NavController {
// add the views to the // add the views to the
for (i = 0; i < insertViews.length; i++) { for (i = 0; i < insertViews.length; i++) {
view = insertViews[i]; view = insertViews[i];
assert(view, 'view must be non null');
this._insertViewAt(view, ti.insertStart + i); this._insertViewAt(view, ti.insertStart + i);
} }
@ -433,14 +440,15 @@ export class NavControllerBase extends Ion implements NavController {
} }
// huzzah! let us transition these views // huzzah! let us transition these views
this._transition(enteringView, leavingView, opts, resolve); this._transition(enteringView, leavingView, opts, ti.resolve);
} else { } else {
// they're inserting/removing the views somewhere in the middle or // they're inserting/removing the views somewhere in the middle or
// beginning, so visually nothing needs to animate/transition // beginning, so visually nothing needs to animate/transition
// resolve immediately because there's no animation that's happening // resolve immediately because there's no animation that's happening
resolve(true, false); ti.resolve(true, false);
} }
return true;
} }
/** /**
@ -488,17 +496,15 @@ export class NavControllerBase extends Ion implements NavController {
this._zone.run(this._didLoad.bind(this, view)); this._zone.run(this._didLoad.bind(this, view));
} }
_viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction) { _viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction): boolean {
const promises: Promise<any>[] = []; const promises: Promise<any>[] = [];
const reject = ti.reject;
const resolve = ti.resolve;
if (leavingView) { if (leavingView) {
const leavingTestResult = leavingView._lifecycleTest('Leave'); const leavingTestResult = leavingView._lifecycleTest('Leave');
if (leavingTestResult === false) { if (leavingTestResult === false) {
// synchronous reject // synchronous reject
reject((leavingTestResult !== false ? leavingTestResult : `ionViewCanLeave rejected`)); ti.reject((leavingTestResult !== false ? leavingTestResult : `ionViewCanLeave rejected`));
return false; return false;
} else if (leavingTestResult instanceof Promise) { } else if (leavingTestResult instanceof Promise) {
// async promise // async promise
@ -511,7 +517,7 @@ export class NavControllerBase extends Ion implements NavController {
if (enteringTestResult === false) { if (enteringTestResult === false) {
// synchronous reject // synchronous reject
reject((enteringTestResult !== false ? enteringTestResult : `ionViewCanEnter rejected`)); ti.reject((enteringTestResult !== false ? enteringTestResult : `ionViewCanEnter rejected`));
return false; return false;
} else if (enteringTestResult instanceof Promise) { } else if (enteringTestResult instanceof Promise) {
// async promise // async promise
@ -521,19 +527,18 @@ export class NavControllerBase extends Ion implements NavController {
if (promises.length) { if (promises.length) {
// darn, async promises, gotta wait for them to resolve // darn, async promises, gotta wait for them to resolve
Promise.all(promises) Promise.all(promises).then((values: any[]) => {
.then((values: any[]) => {
if (values.some(result => result === false)) { if (values.some(result => result === false)) {
reject(`ionViewCanEnter rejected`); ti.reject(`ionViewCanEnter rejected`);
} else { } else {
this._postViewInit(enteringView, leavingView, ti, resolve); this._postViewInit(enteringView, leavingView, ti);
} }
}).catch(reject); }).catch(ti.reject);
return true;
} else { } else {
// synchronous and all tests passed! let's move on already // synchronous and all tests passed! let's move on already
this._postViewInit(enteringView, leavingView, ti, resolve); return this._postViewInit(enteringView, leavingView, ti);
} }
return true;
} }
_transition(enteringView: ViewController, leavingView: ViewController, opts: NavOptions, resolve: TransitionResolveFn) { _transition(enteringView: ViewController, leavingView: ViewController, opts: NavOptions, resolve: TransitionResolveFn) {
@ -678,28 +683,31 @@ export class NavControllerBase extends Ion implements NavController {
} }
_trnsFinish(transition: Transition, opts: NavOptions, resolve: TransitionResolveFn) { _trnsFinish(transition: Transition, opts: NavOptions, resolve: TransitionResolveFn) {
const hasCompleted = transition.hasCompleted;
const enteringView = transition.enteringView;
const leavingView = transition.leavingView;
// mainly for testing // mainly for testing
let enteringName: string; let enteringName: string;
let leavingName: string; let leavingName: string;
let hasCompleted = transition.hasCompleted;
if (hasCompleted) { if (hasCompleted) {
// transition has completed (went from 0 to 1) // transition has completed (went from 0 to 1)
if (transition.enteringView) { if (enteringView) {
enteringName = transition.enteringView.name; enteringName = enteringView.name;
this._didEnter(transition.enteringView); this._didEnter(enteringView);
} }
if (transition.leavingView) { if (leavingView) {
leavingName = transition.leavingView.name; leavingName = leavingView.name;
this._didLeave(transition.leavingView); this._didLeave(leavingView);
} }
this._cleanup(transition.enteringView); this._cleanup(enteringView);
} else { } else {
// If transition does not complete, we have to cleanup anyway, because // If transition does not complete, we have to cleanup anyway, because
// previous pages in the stack are not hidden probably. // previous pages in the stack are not hidden probably.
this._cleanup(transition.leavingView); this._cleanup(leavingView);
} }
if (transition.isRoot()) { if (transition.isRoot()) {
@ -754,7 +762,7 @@ export class NavControllerBase extends Ion implements NavController {
const views = this._views; const views = this._views;
const index = views.indexOf(view); const index = views.indexOf(view);
assert(index > -1, 'view must be part of the stack'); assert(index > -1, 'view must be part of the stack');
if (index > -1) { if (index >= 0) {
views.splice(index, 1); views.splice(index, 1);
} }
} }
@ -771,10 +779,13 @@ export class NavControllerBase extends Ion implements NavController {
// ok, cleanup time!! Destroy all of the views that are // ok, cleanup time!! Destroy all of the views that are
// INACTIVE and come after the active view // INACTIVE and come after the active view
const activeViewIndex = this.indexOf(activeView); const activeViewIndex = this.indexOf(activeView);
const views = this._views;
let reorderZIndexes = false; let reorderZIndexes = false;
for (var i = this._views.length - 1; i >= 0; i--) { let view: ViewController;
var view = this._views[i]; let i: number;
for (i = views.length - 1; i >= 0; i--) {
view = views[i];
if (i > activeViewIndex) { if (i > activeViewIndex) {
// this view comes after the active view // this view comes after the active view
// let's unload it // let's unload it
@ -791,12 +802,11 @@ export class NavControllerBase extends Ion implements NavController {
} }
} }
if (!this._isPortal) { if (!this._isPortal && reorderZIndexes) {
if (reorderZIndexes) { for (i = 0; i < views.length; i++) {
this._views.forEach(view => { view = views[i];
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer); view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer);
});
} }
} }
} }
@ -867,7 +877,6 @@ export class NavControllerBase extends Ion implements NavController {
this._app.viewWillUnload.emit(view); this._app.viewWillUnload.emit(view);
} }
getActiveChildNav(): any { getActiveChildNav(): any {
return this._children[this._children.length - 1]; return this._children[this._children.length - 1];
} }