EmberData | Deprecate Proxies
Summary
Deprecates usage of proxy apis provided by Ember.ObjectProxy
, Ember.PromiseProxyMixin
and Ember.ArrayProxy
in favor of Promises, Native Arrays, and Native Proxies where appropriate.
Specifically this affects RecordArray
AdapterPopulatedRecordArray
, ManyArray
, PromiseArray
, and PromiseRecord
but not PromiseBelongsTo
.
Motivation
Historically EmberData built many presentation classes overtop of Framework primitives out of necessity. Native Proxies did not yet exist, Promises were relatively unheard of, and async state management was the Wild West.
Today we have better native primitives available to us, affording us the opportunity to significantly simplify these presentation objects and better align them with user expectations in the modern Javascript world and Octane Ember.
Importantly, this simplification will allow for us to address the performance of the most expensive costs of managing and presenting data. It will also sever one of the last entanglements the core of EmberData has with the Framework. While this RFC does not in itself enable Ember-less usage of EmberData, it does in effect make this a near possibility.
Transition Path
PromiseRecord|PromiseArray
id: 'ember-data:deprecate-promise-proxies'
Accessing any value on the proxy that is not a promise method will trigger a deprecation. This is similar in effect to RFC 795. Additionally we deprecate promise state flags, this includes deprecating the flags kept in RFC 795.
Affected APIs: store.findRecord
, store.queryRecord
, model.save
, store.findAll
and store.query
Resolution:
await
the returned promise to receive the value to interact with. For promise state flags consider using ember-promise-helpers
RecordArray|AdapterPopulatedRecordArray|ManyArray
id: 'ember-data:deprecate-ember-array-like'
Utilizing EmberObject APIs or ArrayLike APIs that do not correlate to Native Array APIs will be deprecated.
- Affected APIs:
store.query|findAll|peekAll
andhasMany
relationships on@ember-data/model
- Resolution: Convert to the corresponding native array API. In the most common case of
toArray()
this means to useslice()
instead.
PromiseBelongsTo | Model.errors
Since there is no path for a PromiseProxy to not exist for belongsTo relationships, deprecating this promise proxy is left for the deprecation of Model / belongsTo more broadly.
- Affected APIs: async
belongsTo
relationships on instances of@ember-data/model
,errors
property on instance of@ember-data/model
In the interest of parity and in order to make native property access usage easier to refactor to we considered converting Errors and PromiseBelongsTo into native proxies which would allow dot notation access to work. However, for PromiseBelongsTo this would encourage not resolving the value before interacting with it, and encouraging folks to refactor towards await
before use is key for the next stage in which async relationships will not exist at all in their current form. For this reason, we choose to leave this Proxy as-is. For Errors
we have the complication that Errors is a recursive proxy that functions as an ArrayProxy
an ObjectProxy
and its own class. We prefer to find a replacement API that would not have the confusion of both errors.name[0]
and errors[0]
being valid interactions.
We would note that even if Model / belongsTo are not deprecated before 5.0, their replacements will be available.
How We Teach This
Would the acceptance of this proposal mean the Ember guides must be re-organized or altered? Does it change how Ember is taught to new users at any level?
No, the current guides do not make use of proxy behavior.
Does it mean we need to put effort into highlighting the replacement functionality more? What should we do about documentation, in the guides related to this feature?
We should likely create examples of loading and working with async data within components, as it is not always the case that users resolve data in a parent component or route before passing it down. Generally this means surfacing patterns around resources
and async template helpers like ember-promise-helpers
.
How should this deprecation be introduced and explained to existing Ember users?
The APIs were necessary in the classic world, but not in the Octane world. This simplification will not only allow for us to reduce the size, complexity and performance costs of these classes while also aligning their usage with the "just Javascript" mental model.
Drawbacks
As with all deprecations, apps will experience some churn. For apps using EmberData, the churn in the 4.x cycle is likely to be high, of which this will be yet-another contributing factor.
Alternatives
The alternative (not doing this) would prevent deprecation and removal of classic/legacy ember framework code more broadly, as well as it would prevent EmberData from progressing towards being decoupled from the framework and eliminating performance bottlenecks. The cost of this legacy infrastructure is as high as 30% of the overall runtime cost of EmberData.