emberjs / ember.js

Ember.js - A JavaScript framework for creating ambitious web applications
https://emberjs.com
MIT License
22.46k stars 4.22k forks source link

@tracked: lazy evaluation #18118

Open buschtoens opened 5 years ago

buschtoens commented 5 years ago

While investigating #18075, I noticed a minor issue, that persists even after the change to WeakMap in #18091, because of the lazy evaluation

class Foo {
  @service someService;

  @tracked someProp = this.someService.serviceProp;
}

Assume Foo gets created by a container lookup or get manually called setOwner on.

Intuitively I would expect the above code to work. And it does. If this.someProp is only accessed later in the template or in init, everything works fine.

However, if you already access this.someProp in the constructor, you get a TypeError, because this.someService is undefined.

While I understand why, I still think this is inconsistent. If we decide to keep lazy evaluation of the initializers, we need to document it well. Would the new static decorators proposal support lazy evaluation in the first place?

pzuraq commented 5 years ago

@buschtoens this should work in all cases for framework classes, all base classes should be assigning the owner in the root constructor, before any subclasses assign their fields. Are you manually assigning the owner to a class?

buschtoens commented 5 years ago

Yes, in this case the class was not created through the container, but instantiated manually. Should we declare manual instantiation an anti-pattern and instead require the creation through the container?

pzuraq commented 5 years ago

If you need access to the container, I would tend to say yes. The way most container classes work now is essentially:

class GlimmerComponent {
  constructor(owner) {
    setOwner(this, owner);
  }
}

This is how all subclasses are able to immediately access the owner and injections. You could setup your own classes to do something like this, or you could avoid accessing injections until after you assign the owner in general. Unfortunately, we cannot safely give the owner to a class in any other way, so you do have to do all access after setOwner is called somewhere 😕

buschtoens commented 5 years ago

Cool. I can live with that. 👍

Maybe we should add a note about this somewhere in the guides? I can imagine that more people will start instantiating native utility classes themselves, now that it's officially supported.