The _super method points to the wrong method when after an async operation.
For instance, assuming that a super beforeModel exists for a route, the following will return two different super methods before and after the await:
async beforeModel() {
console.log('Before await super: ' + this._super.name);
await loadAccess();
console.log('After await super: ' + this._super.name);
}
A longer version that demonstrates the issue using promises is in this twiddle.
The cause is that this is not a proxied version of the class instance, but the instance itself. Thus _super is scoped to the instance context rather than the execution context.
For example, in ember-utils/lib/super.js, _super is bound in the superWrapper function, which assumes the function being called will make no asynchronous calls:
function superWrapper() {
let orig = this._super;
this._super = superFunc;
let ret = func.apply(this, arguments);
this._super = orig;
return ret;
}
The workaround is to save the _super method at the beginning of any method that plans to use asynchronous code, and then use the saved method:
async beforeModel() {
let { _super } = this;
await loadAccess();
_super.call(this, ...arguments);
}
The cleanest approach would be to use the Proxy object to wrap the original this and provide an overridden _super method that calls the correct super method, then pass this into the function in the wrapper, essentially creating an execution context for the method call.
However, Proxy does not yet seem to be supported for Internet Explorer, so depending what browsers Ember is supporting, this may not be feasible.
Unfortunately, I don't see another way that handles all the edge cases, so this might be another case of documenting the issue and providing the workaround until enough browsers support Proxy to implement the full solution.
A progressive solution could be used that tests for Proxy and uses that if it exists, and falls back to the old implementation if not; though that makes the application behave different on different platforms, which makes the issue even harder to debug when it happens.
@fastfedora ya, I'm not sure how this can be fixed without a hefty performance penalty (it's been a known limitation of user-land _super helper) :(.
As we transition to ES6 objects with super, they will essentially do exactly like your "work-around" does, but under the hood...
The workaround you recommended, is the same one we have been recommending. Before async and await the pain wasn't nearly as bad. But clearly with the increased async/await usage the pain will continue to grow. Hopefully we can pave the road to ES6 classes sooner, so the ergonomics don't suffer (as you have also noticed).
@fastfedora also good sleuthing, and great issue writeup!
This issue with _super annoys the crap out of me...
Glad Ember will be moving to ES6 classes. I used React before and after they moved to ES6 classes and it was a large improvement. Native ES6 classes should get rid of the super problems entirely.
@fastfedora the big blocker for us has been decorators, but we are just going to push that forward and call it a day :)
Just got bit by this "gotcha", thanks for the writeup @fastfedora!
@0xadada @buschtoens @fastfedora @stefanpenner is this still an issue, perhaps we should close or create a new reproduction of this, what do you think?
Closing for now, feel free to re-open if you can reproduce in the current release of Ember.
Most helpful comment
Just got bit by this "gotcha", thanks for the writeup @fastfedora!