-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plots.resize: promises should always be resolved #4392
Changes from 3 commits
deb32ff
040d6ac
5ee431e
5e71cff
14f518f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -412,6 +412,24 @@ describe('Test Plots', function() { | |||
.then(done); | ||||
}); | ||||
}); | ||||
|
||||
describe('returns Promises', function() { | ||||
afterEach(destroyGraphDiv); | ||||
|
||||
it('should resolve them all', function(done) { | ||||
gd = createGraphDiv(); | ||||
var p = []; | ||||
Plotly.newPlot(gd, [{y: [5, 2, 5]}]) | ||||
.then(function() { | ||||
p.push(Plotly.Plots.resize(gd)); | ||||
p.push(Plotly.Plots.resize(gd)); | ||||
p.push(Plotly.Plots.resize(gd)); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool. Thanks for pointing this out. I'm wondering though, why should the second There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I thought that rejecting made more sense since the resize has not happened yet. The goal is to clearly tell the caller that the operation is not completed. Listening to the log is probably not ideal for this purpose. Another possibility would be to resolve all pending promises once the resize operation is done. We could keep all the I'm not sure what's the best behavior to adopt here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As a customer of the promise both resolving or rejecting the promise can make sense. If resolving instead of rejecting, providing a state that makes it clear that a resize has occurred or not would be necessary to add value vs. rejection: callers don't need to keep track of the number of in-progress requests anymore, they only need to wait for a promise to resolve with a success state. --Actually if resize can take longer than the debounce timeout, true/false state on resolve will not be of any use. Seems pretty clear this could happen, which means a counter from the caller's side is still the best bet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so according to @Marc-Andre-Rivet, it seems like resolving/rejecting versus resolving true/ false is equivalent. It is, therefore, a matter of preference/philosophy for @plotly/plotly_js. I don't have a strong preference as long as all promises are fulfilled or rejected. Just let me know what you would prefer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A caller probably doesn't actually care that another resize delayed the redraw, they just want to know when the resize is really truly done, even if it takes 10 sec because someone keeps spamming resize calls. So what if instead we resolve all of these promises at the same time, whenever the redraw really happens? If I'm understanding this correctly, we can do that by simply resolving the first promise with the new promise we've just made - ie store it in a var rather than just > p=new Promise((resolve, reject) => {window.res=resolve})
> p.then(v=>console.log('p: ', v))
> p2=new Promise((resolve, reject) => {window.res2=resolve})
> p2.then(v=>console.log('p2: ', v))
> res(p2) // this doesn't resolve p, because we're resolving with another promise
> p
< Promise {<pending>}
> res2(42) // this resolves p2 AND p
p2: 42
p: 42
> p
< Promise {<resolved>: 42} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcjohnson Nice! I was not aware of that impl detail for Here's a scenario where we may need to do more than wait for a single resize operation to be triggered and completed in order to resolve the promise? Doing away with counters on the caller's side entirely. Given that Line 105 in deb32ff
[0ms] resize request No.1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call @Marc-Andre-Rivet - this is a really helpful scenario. There's not very much that happens async in plotly.js, and in fact in a resize I'd think the vast majority of these would already be done. For the most part it's MathJax and map data, and once you've drawn the graph once, on a resize you already have the correct data so these operations should complete synchronously. But there may be some edge cases where it's still async... Then I think the important thing is that any new call to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commit 040d6ac resolves all promises instead of rejecting them. About overlapping requests:
I am not familiar with that part of the code so I can't say how much work it would involve. Maybe @etpinard could give us an idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should all be manageable from within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the following is simpler and does the right thing: 5ee431e See the pattern in action at https://codepen.io/antoinerg/pen/YzPXyJv?editors=1002 |
||||
return Promise.all(p); | ||||
}) | ||||
.catch(failTest) | ||||
.then(done); | ||||
}); | ||||
}); | ||||
}); | ||||
|
||||
describe('Plots.purge', function() { | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Took me a while and drawing some timing diagrams to be sure I agreed with this, but I think you've got it 🏆
Only thing I might suggest is when we finally get to this
resolve(gd)
, should we alsodelete gd._resolveResize
? Otherwise the next time someone resizes 10 minutes later, there will still be aresolveLastResize(p)
call. In principle it's OK to resolve the same promise more than once, but it feels nicer not to, also then we don't need to worry about it duringpurge
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old promise resolver is now deleted in 5ee431e !