-
-
Notifications
You must be signed in to change notification settings - Fork 36
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
Add .cancel()
#17
Add .cancel()
#17
Conversation
Thanks for merging #16. 👍 I've rebased this one. |
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 work @timdp !
index.js
Outdated
|
||
class AbortError extends Error { | ||
constructor(message) { // eslint-disable-line no-useless-constructor | ||
super(message); |
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.
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.
I believe you can remove the // eslint-disable-line no-useless-constructor
as well now.
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.
Done!
I'd briefly pushed a version that included multipipe
as a dependency because I accidentally npm-installed that in the wrong terminal tab. Make sure you don't accidentally merge that one. Sorry about that.
index.js
Outdated
@@ -1,34 +1,48 @@ | |||
'use strict'; | |||
|
|||
const defer = require('p-defer'); |
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.
Remove empty line above this statement
Thanks! |
Just fixed a typo in the readme. The code hasn't changed. |
What should happen in that case though? Never resolving the promise? That would mean any promise after would never resolve. Resolve with no value? Promises after might depend on some value that are to be passed through.
Me neither |
I wonder, now that the official promise cancelation is dead (Meaning, we don't risk being incompatible with the offical spec), should we use |
Yeah, I'm not saying an ever-pending promise is a great solution. I just wanted to mention the common case of wanting to cancel with the intention of not running continuations. I'm more than happy to change abort to cancel. One little issue that it raises is whether the error should be a CancelationError (US English) or a CancellationError (UK English). |
I was really asking. What do you think should happen? I'm open to suggestion for solving that use-case.
Why not just |
That's the thing, I don't know. :-) I suppose there's no cleaner way than a catch with an instanceof to swallow the error.
Bluebird calls it CancellationError so one of my packages also does that for the sake of consistency. It's always slightly annoyed me, even though most Americans I know also seem to throw some British influences into their English as well. Personally, I'm not a fan of CancelError because I think you'd be less likely to call it that in spoken or written English. I'd go so far as to say AbortError should be AbortionError, but there are obvious reasons not to call it that. As a reference, Uber has something called a cancellation fee. Interestingly, they also use double L, while their language selector explicitly distinguishes between US English and UK English. Could be laziness on their part though. |
In my opinion, it feels like when cancelling a promise, nothing that comes after that step should be executed. So resolving with an empty value doesn't feel right. So I'm in doubt between throwing something or just do nothing. And to be honest, I'm more in favour of doing nothing because, as the method implies, it is aborted/cancelled. To me it doesn't feel right that still some code inside the chain is being excited, not even with a specific error object because it was cancelled entirely. It's just my opinion :). The thing I wonder though when you do that, does that mean we have a dangling promise that can not be cleaned up by the GC? Because it's in an idle state (neither resolved or rejected)? I don't think so, but it might. |
I assume it'll be problematic for GC as long if the promise remembers its An alternative could be to always resolve and have a Since this is never going to get standardized, I think the closest we can get is throwing an error. |
I just ran this basic memory benchmark on Node 6: const run = () => {
global.gc()
console.log('before:', process.memoryUsage().heapUsed)
for (let i = 0; i < 1000000; ++i) {
new Promise((resolve, reject) => {}).then(() => {})
}
setTimeout(() => {
global.gc()
console.log('after: ', process.memoryUsage().heapUsed)
setTimeout(run, 5000)
}, 5000)
}
run() First 3 iterations on my machine:
So actually, it wouldn't be an issue in terms of performance. |
I'd be open to an option to just resolve with nothing instead of throwing, but I don't want it as the default behavior and it should be a separate pull request. We can't do nothing, for example, |
Let's go with Why |
Okay, PR updated. Branch name doesn't make sense anymore though. |
Awesome. Thanks for your patience @timdp :) |
No problem. I prefer to get things right. :) Thanks for merging! |
I encountered an issue after upgrading to delay@2.0 when running a webpack build with UglifyJS: https://travis-ci.org/cncjs/cncjs/jobs/215250557#L7209 Do you have any clues on that? Thanks. |
@cheton Uglify doesn't support ES2015 syntax. See sindresorhus/ama#446. |
As suggested in #15.
Notes:
abort()
throws anAbortError
. Perhaps that behavior should be optional? I usually find myself wanting to cancel everything that follows, and I'd rather not add acatch
in those cases.p-defer
, which is lightweight, but still relevant.