ember-data: Return a Promise from Model.save()#795
Conversation
|
Would it make more sense to return a vanilla Promise? Most of RSVP is already available in native Promise. (I'm guessing RSVP will eventually be deprecated too) |
|
@sandstrom I like your suggestion. Might be something we want to RFC to get off of RSVP now that we are past IE11. I'll talk to Chris tomorrow! |
|
There are a few hairy parts where we were relying on private RSVP API's to guard against dangling promises. Specifically here...So alongside this PR, we are going to introduce a deprecation for RSVP. |
|
Added final comment period, That said I would like to revisit the decision to add the state-flags. I think there's a strong case for it being a separate util, even if an official one. @rwjblue @hjdivad @igorT thoughts? Ignore the specific package name, this is just hand-wave sketch, but if you have thoughts on package name to give them: This would more or less look something like: class PromiseState extends Promise {
@tracked isRejected = false;
@tracked isResolved = false;
@tracked isPending = true;
}
// in JS (promiseState would weakmap to a PromiseState to provide stable return for same promise)
import { promiseState } from "@ember-data/template-utils";
//...
const state = promiseState(promise);
//...
if (state.isPending) {
} |
2c6ff32 to
8a94128
Compare
I agree that an util function would be way better - especially for teaching. But I don't see how such an util function could be implemented. As far as I know there is no way to synchronously determine a JavaScript Promise's state. |
|
@jelhan There has been a few approaches I have taken (the first being pulled from promise many array implementation). I'm unsure of what these two examples don't cover or if you were thinking about something else. One downside to the util approach is for users to fish though their code to replace. However, in conjunction with #796, I could see us not concerning ourselves with the derived state. |
Thanks a lot for sharing this examples. I used the The state of a Promise, which has been resolved before constructing a I think that's the reason why @runspired proposes to have a I fear that this API limitation would be very confusing to consumers. Let me illustrate using one very confusing edge case based on the API proposed by @runspired in #795 (comment): const promise = post.save();
await promise;
const state = promiseState(promise);
console.log('isPending', state.isPending); // true
console.log('isResolved', state.isResolved); // false
// do something async, which is totally unrelated,
// but causes later code to be executed in the next tick
await Promise.resolve();
console.log('isPending', state.isPending); // false
console.log('isResolved', state.isResolved); // true🤯 |
|
@jelhan Really nice points. Just a few notes...
But I guess it would really trip people up if they used those state flags for non UI purposes. So I agree with your take and runspireds. |
|
@jelhan while it is true that potential for it to be wrong by one-tick exists, the WeakMap solution effectively solves that problem for the 99% case. const promise = record.save();
const state = promiseState(promise);
// all state flags are correct before the await
await promise;
// all state flags are still correct after the await
// all state 2 flags are immediately correct, because state2 === state
const state2 = promiseState(promise);For the 1% case where someone fails to call promiseState until after the promise has resolved, there are two outcomes:
|
Partial dup of #362 (comment) with improvements. Specifically the addition of derived state to the promise wrapper.
rendered