Skip to content

Commit

Permalink
[refactor] Common function for Ember-App instance destruction
Browse files Browse the repository at this point in the history
  • Loading branch information
Arjan Singh committed Nov 1, 2016
1 parent b8223ee commit 52a22e6
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 49 deletions.
87 changes: 45 additions & 42 deletions src/ember-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,34 @@ class EmberApp {
});
}

/**
* @private
*
* Creates a destroy function to destroy the created `ApplicationInstance`.
*
* @param {Object} The Result object that contains the application instance to be destroyed.
* @param {Integer} How long to wait before manually destroying the application instance. Ignored if its value is 0.
*
* @returns {Function} The destructor function.
*/
destroyAppInstance(result, timeout) {
const instance = result.instance;

if (!timeout) return () => instance.destroy();

// start a timer to destroy the appInstance forcefully in the given ms.
// This is a failure mechanism so that node process doesn't get wedged if the `visit` never completes.
const destructionTimer = setTimeout(function() {
instance.destroy();
result.error = new Error(`App instance was forcefully destroyed in ${timeout}ms`);
}, timeout);

return () => {
clearTimeout(destructionTimer);
instance.destroy();
};
}

/**
* @private
*
Expand All @@ -221,25 +249,22 @@ class EmberApp {
* @param {Object} bootOptions An object containing the boot options that are used by
* by ember to decide whether it needs to do rendering or not.
* @param {Object} result
* @param {Integer} How long to wait before manually destroying the application instance. Ignored if its value is 0.
*
* @return {Promise<instance>} instance
*/
visitRoute(path, fastbootInfo, bootOptions, result) {
let instance;

visitRoute(path, fastbootInfo, bootOptions, result, destroyAppInstanceInMs) {
return this.buildAppInstance()
.then(appInstance => {
instance = appInstance;
result.instance = instance;
registerFastBootInfo(fastbootInfo, instance);

return instance.boot(bootOptions);
result.instance = appInstance;
registerFastBootInfo(fastbootInfo, appInstance);
result.destroyInstance = this.destroyAppInstance(result, destroyAppInstanceInMs);
return appInstance.boot(bootOptions);
})
.then(() => result.instanceBooted = true)
.then(() => instance.visit(path, bootOptions))
.then(() => waitForApp(instance))
.then(() => {
return instance;
});
.then(() => result.instance.visit(path, bootOptions))
.then(() => waitForApp(result.instance))
.then(() => result.instance);
}

/**
Expand Down Expand Up @@ -269,7 +294,7 @@ class EmberApp {
let res = options.response;
let html = options.html || this.html;
let disableShoebox = options.disableShoebox || false;
let destroyAppInstanceInMs = options.destroyAppInstanceInMs;
let destroyAppInstanceInMs = parseInt(options.destroyAppInstanceInMs, 10) || 0;

let shouldRender = (options.shouldRender !== undefined) ? options.shouldRender : true;
let bootOptions = buildBootOptions(shouldRender);
Expand All @@ -287,42 +312,20 @@ class EmberApp {
fastbootInfo: fastbootInfo
});

let destroyAppInstanceTimer;
if (parseInt(destroyAppInstanceInMs, 10) > 0) {
// start a timer to destroy the appInstance forcefully in the given ms.
// This is a failure mechanism so that node process doesn't get wedged if the `visit` never completes.
destroyAppInstanceTimer = setTimeout(function() {
if (instance && !result.instanceDestroyed) {
result.instanceDestroyed = true;
result.error = new Error('App instance was forcefully destroyed in ' + destroyAppInstanceInMs + 'ms');
instance.destroy();
}
}, destroyAppInstanceInMs);
}

let instance;
return this.visitRoute(path, fastbootInfo, bootOptions, result)
.then(appInstance => {
instance = appInstance;
})
return this.visitRoute(path, fastbootInfo, bootOptions, result, destroyAppInstanceInMs)
.then(() => result.instanceBooted = true)
.then(() => result.instance.visit(path, bootOptions))
.then(() => waitForApp(result.instance))
.then(() => {
if (!disableShoebox) {
// if shoebox is not disabled, then create the shoebox and send API data
createShoebox(doc, fastbootInfo);
}
})
.catch(error => result.error = error)
.catch(error => result.error = result.error || error)
.then(() => result._finalize())
.finally(() => {
if (instance && !result.instanceDestroyed) {
result.instanceDestroyed = true;
instance.destroy();

if (destroyAppInstanceTimer) {
clearTimeout(destroyAppInstanceTimer);
}
}
});
.finally(() => result.destroyInstance());
}

/**
Expand Down
13 changes: 6 additions & 7 deletions src/result.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ const HTMLSerializer = new SimpleDOM.HTMLSerializer(SimpleDOM.voidMap);
* method.
*/
class Result {
constructor(options) {
this.instanceBooted = false;
this.instanceDestroyed = false;
constructor(options) {
this.instanceBooted = false;
this._doc = options.doc;
this._html = options.html;
this._fastbootInfo = options.fastbootInfo;
Expand Down Expand Up @@ -84,10 +83,10 @@ class Result {
return this;
}

_finalizeMetadata(instance) {
if (this.instanceBooted) {
this.url = instance.getURL();
}
_finalizeMetadata(instance) {
if (this.instanceBooted) {
this.url = instance.getURL();
}

let response = this._fastbootInfo.response;

Expand Down

0 comments on commit 52a22e6

Please sign in to comment.