This repository has been archived by the owner. It is now read-only.

Don't reject promises to signal cancellation #141

Closed
jakearchibald opened this Issue Feb 22, 2016 · 26 comments

Comments

Projects
None yet
6 participants
@jakearchibald

https://w3c.github.io/web-animations/#canceling-an-animation-section

Just got caught out by this. An animation being stopped before completion doesn't feel like an exceptional state, certainly not something that should appear as an error in devtools.

This is a good usecase for cancelable promises https://github.com/domenic/cancelable-promise (+@domenic).

Alternatively, the promise could be .done rather than .finished and resolve to a value indicating whether the animation played to completion.

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Feb 22, 2016

Contributor

I don't quite understand the issue. Just for clarification, it's not being stopped (paused), it's being abandoned. At that point, no fill, nothing, happens. All computed timing parameters go to null. This is what happens when, for example, you have a CSS animation running on an element and the element gets detached from the tree, or when a CSS transition gets replaced but another transition.

Cancelable promises sound like a better fit, but until they exist this seems preferable to relying on authors to check a promise resolution value (since they'll almost certainly fail to do so and then their app will break in the rare case where the animation is cancelled).

(We've had this in Firefox OS where apps would break because they were waiting on a transitionend event and then something triggered a re-render which blew away the part of the DOM tree that they were waiting on. A promise rejection in that case would have spared us a lot of bugs!)

What's the devtools issue you're seeing?

Contributor

birtles commented Feb 22, 2016

I don't quite understand the issue. Just for clarification, it's not being stopped (paused), it's being abandoned. At that point, no fill, nothing, happens. All computed timing parameters go to null. This is what happens when, for example, you have a CSS animation running on an element and the element gets detached from the tree, or when a CSS transition gets replaced but another transition.

Cancelable promises sound like a better fit, but until they exist this seems preferable to relying on authors to check a promise resolution value (since they'll almost certainly fail to do so and then their app will break in the rare case where the animation is cancelled).

(We've had this in Firefox OS where apps would break because they were waiting on a transitionend event and then something triggered a re-render which blew away the part of the DOM tree that they were waiting on. A promise rejection in that case would have spared us a lot of bugs!)

What's the devtools issue you're seeing?

@dstockwell

This comment has been minimized.

Show comment
Hide comment
@dstockwell

dstockwell Feb 22, 2016

Contributor

What's the devtools issue you're seeing?

I assume the issue is that if you don't handle rejection and the animation is cancelled then the rejection is logged to the console.

Contributor

dstockwell commented Feb 22, 2016

What's the devtools issue you're seeing?

I assume the issue is that if you don't handle rejection and the animation is cancelled then the rejection is logged to the console.

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Feb 23, 2016

@dstockwell

I assume the issue is that if you don't handle rejection and the animation is cancelled then the rejection is logged to the console.

Yep! Using a rejection here doesn't really fit in with https://www.w3.org/2001/tag/doc/promises-guide#rejections-should-be-exceptional

@dstockwell

I assume the issue is that if you don't handle rejection and the animation is cancelled then the rejection is logged to the console.

Yep! Using a rejection here doesn't really fit in with https://www.w3.org/2001/tag/doc/promises-guide#rejections-should-be-exceptional

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Feb 23, 2016

@birtles

Cancelable promises sound like a better fit, but until they exist this seems preferable to relying on authors to check a promise resolution value

Will the animations spec be able to transition to cancelable promises in future? Feels like compatibility might get in the way.

With fetch() we held off on defining cancellation until a proper solution was ready.

@birtles

Cancelable promises sound like a better fit, but until they exist this seems preferable to relying on authors to check a promise resolution value

Will the animations spec be able to transition to cancelable promises in future? Feels like compatibility might get in the way.

With fetch() we held off on defining cancellation until a proper solution was ready.

@jakearchibald jakearchibald changed the title from Don't abort promises to signal cancellation to Don't reject promises to signal cancellation Feb 23, 2016

@dstockwell

This comment has been minimized.

Show comment
Hide comment
@dstockwell

dstockwell Feb 24, 2016

Contributor

@jakearchibald

I'm not sure cancelable promises would help much.

  1. Animation cancellation is exceptional and should usually be handled. An unhandled cancellation would need to be logged to the console and we would be back to the same problem.
  2. We don't have a third state. The animation either finishes or is cancelled.
  3. The issues with fetch cancellation seem different. As I understand it, with fetch() we have only a Promise object as a handle on the fetch request. With web-animations the Animation object is the handle and already has a cancel() function.
Contributor

dstockwell commented Feb 24, 2016

@jakearchibald

I'm not sure cancelable promises would help much.

  1. Animation cancellation is exceptional and should usually be handled. An unhandled cancellation would need to be logged to the console and we would be back to the same problem.
  2. We don't have a third state. The animation either finishes or is cancelled.
  3. The issues with fetch cancellation seem different. As I understand it, with fetch() we have only a Promise object as a handle on the fetch request. With web-animations the Animation object is the handle and already has a cancel() function.
@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Feb 25, 2016

@dstockwell

Animation cancellation is exceptional and should usually be handled. An unhandled cancellation would need to be logged to the console and we would be back to the same problem.

I don't think that's the case. Say I want to fade something then remove it from the DOM: http://jsbin.com/fedabep/edit?js,output

If the element is detached from the document before the animation completes (eg if it's a single page app and the view changes), that's fine, that view has gone anyway. I wouldn't expect errors in my console.

If cancellation is exceptional, why is the equivalent event named "cancel" and not "error"?

We don't have a third state. The animation either finishes or is cancelled

Just because you don't reject, doesn't mean you can't cancel. Imagine a promise-based version of setTimeout - it can only succeed or cancel, but that isn't a good argument for it rejecting instead of cancelling.

The issues with fetch cancellation seem different. As I understand it, with fetch() we have only a Promise object as a handle on the fetch request. With web-animations the Animation object is the handle and already has a cancel() function.

The API to trigger cancellation is unrelated to what should happen to the promise when the underlying action is canceled.

With fetch we could add a token-based cancellation system today, but we haven't because there isn't a good way to represent this in the promise, aside from rejecting, which is the wrong thing to do.

@dstockwell

Animation cancellation is exceptional and should usually be handled. An unhandled cancellation would need to be logged to the console and we would be back to the same problem.

I don't think that's the case. Say I want to fade something then remove it from the DOM: http://jsbin.com/fedabep/edit?js,output

If the element is detached from the document before the animation completes (eg if it's a single page app and the view changes), that's fine, that view has gone anyway. I wouldn't expect errors in my console.

If cancellation is exceptional, why is the equivalent event named "cancel" and not "error"?

We don't have a third state. The animation either finishes or is cancelled

Just because you don't reject, doesn't mean you can't cancel. Imagine a promise-based version of setTimeout - it can only succeed or cancel, but that isn't a good argument for it rejecting instead of cancelling.

The issues with fetch cancellation seem different. As I understand it, with fetch() we have only a Promise object as a handle on the fetch request. With web-animations the Animation object is the handle and already has a cancel() function.

The API to trigger cancellation is unrelated to what should happen to the promise when the underlying action is canceled.

With fetch we could add a token-based cancellation system today, but we haven't because there isn't a good way to represent this in the promise, aside from rejecting, which is the wrong thing to do.

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Feb 25, 2016

Contributor

I think there are some apps where you can safely do the same thing whether the animation runs to completion or is aborted part way. There are also a lot where you can't.

That's one of the fundamental problems with SVG animation: it doesn't distinguish between running to completion and cancelling. As a result, you can't cancel a chain of animations. If you cancel one of the links, the next link just treats that the same as finishing and continues the chain.

Forcing apps to explicitly consider what they should do in the case where the animation is aborted (and giving them a console warning when they haven't considered it and that possibility does arise) seems like the most desirable behaviour to me.

It might be that cancellable promises are a better fit for that, but I'm not yet persuaded we should conflate running to completion and abortion like SVG does just in case cancellable promises materialize in the future.

Contributor

birtles commented Feb 25, 2016

I think there are some apps where you can safely do the same thing whether the animation runs to completion or is aborted part way. There are also a lot where you can't.

That's one of the fundamental problems with SVG animation: it doesn't distinguish between running to completion and cancelling. As a result, you can't cancel a chain of animations. If you cancel one of the links, the next link just treats that the same as finishing and continues the chain.

Forcing apps to explicitly consider what they should do in the case where the animation is aborted (and giving them a console warning when they haven't considered it and that possibility does arise) seems like the most desirable behaviour to me.

It might be that cancellable promises are a better fit for that, but I'm not yet persuaded we should conflate running to completion and abortion like SVG does just in case cancellable promises materialize in the future.

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Feb 26, 2016

@birtles

I'm not yet persuaded we should conflate running to completion and abortion like SVG does

That's not what I'm proposing here. With a cancelable promise:

promise.then(val => {
  // It sucessfully finished with value `val`
});

promise.catch(err => {
  // It exceptionally failed with error `err`
});

promise.catchCancel(reason => {
  // The operation canceled before completion with reason `reason`
});

promise.finally(() => {
  // The promise settled in one of the above ways
});

When cancelable promises ship, the API that web animations use is going to be legacy, and something developers will have to hack around. I'm proposing removing those promises until cancelable promises land, or finding a forwards compatible route.

@birtles

I'm not yet persuaded we should conflate running to completion and abortion like SVG does

That's not what I'm proposing here. With a cancelable promise:

promise.then(val => {
  // It sucessfully finished with value `val`
});

promise.catch(err => {
  // It exceptionally failed with error `err`
});

promise.catchCancel(reason => {
  // The operation canceled before completion with reason `reason`
});

promise.finally(() => {
  // The promise settled in one of the above ways
});

When cancelable promises ship, the API that web animations use is going to be legacy, and something developers will have to hack around. I'm proposing removing those promises until cancelable promises land, or finding a forwards compatible route.

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Feb 29, 2016

Contributor

Thanks, that's helpful. I have two questions:

  1. What would be a reason for an exceptional failure for an animation? I'm having a hard time thinking of one which makes me wonder why we need the distinction.

  2. What evidence do we have for cancelable promises materializing in the near future?

Contributor

birtles commented Feb 29, 2016

Thanks, that's helpful. I have two questions:

  1. What would be a reason for an exceptional failure for an animation? I'm having a hard time thinking of one which makes me wonder why we need the distinction.

  2. What evidence do we have for cancelable promises materializing in the near future?

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Feb 29, 2016

@birtles

  1. What would be a reason for an exceptional failure for an animation?

Not sure, maybe all your exceptions are synchronous at the time of calling .animate() or .play().

I'm having a hard time thinking of one which makes me wonder why we need the distinction.

I don't think this reasoning works. Just because something never rejects doesn't mean the distinction isn't important.

Take this:

function randomNum(from, to) {
  return Math.random() * (to - from) + from;
}

The above function never throws, but the distinction does matter. You couldn't replace the return for a throw in the above code without considering what that means, and the impact that would have on usage. Same goes for resolving vs rejecting vs cancelation.

Take this code:

function loadSection(url) {
  return fetch(url).then(createPageElement).then(el => {
    return el.animate([{
      opacity: 0
    }, {
      opacity: 1
    }], 1000).finished;
  })
}

If loadSection(url) resolves, I'd expect to have the new section fully visible on screen. If loadSection(url) rejects, I'd expect there to be an exceptional failure to display this section, and I'd show an error message to the user. Whereas if loadSection(url) cancels, I'd assume another operation had superseded this one, and not show an error message.

  1. What evidence do we have for cancelable promises materializing in the near future?

Fetch needs it, and it's a fundamental part of service workers, which is a fundamental part of progressive web apps, which is hugely important to Chrome right now.

Also, as evidence by this thread, other APIs need it too. Depending on the result here, Web Animations is going to ship a broken API, or have part of the API blocked on cancelable promises. Either is great evidence for why we need cancelable promises.

@birtles

  1. What would be a reason for an exceptional failure for an animation?

Not sure, maybe all your exceptions are synchronous at the time of calling .animate() or .play().

I'm having a hard time thinking of one which makes me wonder why we need the distinction.

I don't think this reasoning works. Just because something never rejects doesn't mean the distinction isn't important.

Take this:

function randomNum(from, to) {
  return Math.random() * (to - from) + from;
}

The above function never throws, but the distinction does matter. You couldn't replace the return for a throw in the above code without considering what that means, and the impact that would have on usage. Same goes for resolving vs rejecting vs cancelation.

Take this code:

function loadSection(url) {
  return fetch(url).then(createPageElement).then(el => {
    return el.animate([{
      opacity: 0
    }, {
      opacity: 1
    }], 1000).finished;
  })
}

If loadSection(url) resolves, I'd expect to have the new section fully visible on screen. If loadSection(url) rejects, I'd expect there to be an exceptional failure to display this section, and I'd show an error message to the user. Whereas if loadSection(url) cancels, I'd assume another operation had superseded this one, and not show an error message.

  1. What evidence do we have for cancelable promises materializing in the near future?

Fetch needs it, and it's a fundamental part of service workers, which is a fundamental part of progressive web apps, which is hugely important to Chrome right now.

Also, as evidence by this thread, other APIs need it too. Depending on the result here, Web Animations is going to ship a broken API, or have part of the API blocked on cancelable promises. Either is great evidence for why we need cancelable promises.

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Feb 29, 2016

Contributor

Thanks, the loadSection example is quite helpful. Unfortunately it's a little hard to reason from that example when it doesn't actually use the finished promise to do anything. Nevertheless, I now have a better sense of the kind of patterns you're concerned about.

I'm still concerned about shipping this API without the finished promise. It's just such a useful part of this API and a lot of our test suite depends on it.

@annevk's comment here is about the most reassuring indication I can find that cancelable promises might actually happen soon-ish. I understand the motivation and desire for this feature, but I'd be really glad to hear of other evidence that this actually happening.

Contributor

birtles commented Feb 29, 2016

Thanks, the loadSection example is quite helpful. Unfortunately it's a little hard to reason from that example when it doesn't actually use the finished promise to do anything. Nevertheless, I now have a better sense of the kind of patterns you're concerned about.

I'm still concerned about shipping this API without the finished promise. It's just such a useful part of this API and a lot of our test suite depends on it.

@annevk's comment here is about the most reassuring indication I can find that cancelable promises might actually happen soon-ish. I understand the motivation and desire for this feature, but I'd be really glad to hear of other evidence that this actually happening.

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Mar 1, 2016

Member

@domenic is making progress. ETA is two months or so, though there's probably some politicking involved too. But it's happening.

And we should do the right thing here. The future is way longer than the past and we'll have lots of regret if the animation API does promises poorly and will always need to be wrapped in try/catch once we get synchronous looking code with async/await.

Member

annevk commented Mar 1, 2016

@domenic is making progress. ETA is two months or so, though there's probably some politicking involved too. But it's happening.

And we should do the right thing here. The future is way longer than the past and we'll have lots of regret if the animation API does promises poorly and will always need to be wrapped in try/catch once we get synchronous looking code with async/await.

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Mar 1, 2016

@birtles

Thanks, the loadSection example is quite helpful. Unfortunately it's a little hard to reason from that example when it doesn't actually use the finished promise to do anything

My point was that .finished may not reject, but a chain of promises involving .finished might. But here's an example using .finished:

aboutBtn.addEventListener('click', async () => {
  await cancelAnyPendingSectionLoad();
  startSpinner();

  try {
    await loadSection('/about/');
  }
  catch (err) {
    displayError(err);
  }
  finally {
    stopSpinner();
  }
});

but I'd be really glad to hear of other evidence that this actually happening

If I spend time compiling reasons and evidence, you might just say "sorry, the evidence I require is in another castle", so help me identify the correct castle 😃

The story so far:

What kinds of additional evidence would help?

@birtles

Thanks, the loadSection example is quite helpful. Unfortunately it's a little hard to reason from that example when it doesn't actually use the finished promise to do anything

My point was that .finished may not reject, but a chain of promises involving .finished might. But here's an example using .finished:

aboutBtn.addEventListener('click', async () => {
  await cancelAnyPendingSectionLoad();
  startSpinner();

  try {
    await loadSection('/about/');
  }
  catch (err) {
    displayError(err);
  }
  finally {
    stopSpinner();
  }
});

but I'd be really glad to hear of other evidence that this actually happening

If I spend time compiling reasons and evidence, you might just say "sorry, the evidence I require is in another castle", so help me identify the correct castle 😃

The story so far:

What kinds of additional evidence would help?

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Mar 1, 2016

Contributor

Thanks Jake! All I was really looking for was Anne's comment that this is happening in ~2 months! That's great. We can wait 2 months. I was just concerned that this was more like 2 years since we've been talking about it for more than 2 years.

Thanks for taking the time to write the extended example too. That makes sense to me.

Contributor

birtles commented Mar 1, 2016

Thanks Jake! All I was really looking for was Anne's comment that this is happening in ~2 months! That's great. We can wait 2 months. I was just concerned that this was more like 2 years since we've been talking about it for more than 2 years.

Thanks for taking the time to write the extended example too. That makes sense to me.

@mik01aj mik01aj referenced this issue in axios/axios Mar 21, 2016

Closed

No Clear way to abort XmlHttpRequest #50

@suzyh suzyh added the affects API label Apr 15, 2016

@bergus

This comment has been minimized.

Show comment
Hide comment
@bergus

bergus Jul 21, 2016

I think @dstockwell had a point here. There is nothing wrong with rejecting a cancelled promise - in fact that's the reasonable choice, as we are not going to fulfill it, and there is no third state.

Of course the title of this issue is correct: Don't reject promises to signal cancellation. We reject promises to signify that no result is available. To signal cancellation, cancellation tokens are used.

Regarding that loadSections example,

If loadSection(url) rejects, I'd expect there to be an exceptional failure to display this section, and I'd show an error message to the user.
Whereas if loadSection(url) cancels, I'd assume another operation had superseded this one, and not show an error message.

that's totally reasonable. However the difference between the two scenarios is not the state of the promise (which should be rejected in both cases), but rather the fact that you have cancelled it.
If you are cancelling the loadSection action, you'd also cancel the action that shows an error message in case of an error - it is not needed any more. Having cancelled the promise, we ignore its results, and that it does reject doesn't matter to us any more.

Here's what such code would look like with the API I'm proposing:

function loadSection(url, token) {
  return fetch(url, token).then(createPageElement).then(el => {
    return el.animate([{
      opacity: 0
    }, {
      opacity: 1
    }], 1000, token).finished;
  })
}

const {token, cancel} = CancelToken.source();
loadSection("", token).catch(showErrorMessage, token);
// at any time:
cancel();

The showErrorMessage is not going to run when token is cancelled.

bergus commented Jul 21, 2016

I think @dstockwell had a point here. There is nothing wrong with rejecting a cancelled promise - in fact that's the reasonable choice, as we are not going to fulfill it, and there is no third state.

Of course the title of this issue is correct: Don't reject promises to signal cancellation. We reject promises to signify that no result is available. To signal cancellation, cancellation tokens are used.

Regarding that loadSections example,

If loadSection(url) rejects, I'd expect there to be an exceptional failure to display this section, and I'd show an error message to the user.
Whereas if loadSection(url) cancels, I'd assume another operation had superseded this one, and not show an error message.

that's totally reasonable. However the difference between the two scenarios is not the state of the promise (which should be rejected in both cases), but rather the fact that you have cancelled it.
If you are cancelling the loadSection action, you'd also cancel the action that shows an error message in case of an error - it is not needed any more. Having cancelled the promise, we ignore its results, and that it does reject doesn't matter to us any more.

Here's what such code would look like with the API I'm proposing:

function loadSection(url, token) {
  return fetch(url, token).then(createPageElement).then(el => {
    return el.animate([{
      opacity: 0
    }, {
      opacity: 1
    }], 1000, token).finished;
  })
}

const {token, cancel} = CancelToken.source();
loadSection("", token).catch(showErrorMessage, token);
// at any time:
cancel();

The showErrorMessage is not going to run when token is cancelled.

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Jul 21, 2016

@bergus my understanding is that rejecting a cancelled promise is wrong, and that the third state is being actively developed in tc39. Let me know if this has changed.

@bergus my understanding is that rejecting a cancelled promise is wrong, and that the third state is being actively developed in tc39. Let me know if this has changed.

@bergus

This comment has been minimized.

Show comment
Hide comment
@bergus

bergus Jul 21, 2016

@jakearchibald Yes, domenic is still developing the third state approach, but it's only stage 1 and there are concerns. I'm just trying to establish an alternative approach that might be more natural and work out better.

bergus commented Jul 21, 2016

@jakearchibald Yes, domenic is still developing the third state approach, but it's only stage 1 and there are concerns. I'm just trying to establish an alternative approach that might be more natural and work out better.

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Jul 21, 2016

Cool. If that approach is adopted we can revisit this.

Cool. If that approach is adopted we can revisit this.

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Jan 25, 2017

Contributor

@jakearchibald @annevk Do you know if cancelable promises going to happen now that Domenic is not working on them?

Contributor

birtles commented Jan 25, 2017

@jakearchibald @annevk Do you know if cancelable promises going to happen now that Domenic is not working on them?

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Jan 25, 2017

Member

They are not. See whatwg/fetch#447 for options we are exploring for Fetch. It would be good if we could align on the exception to reject with and how to expose cancelation.

Member

annevk commented Jan 25, 2017

They are not. See whatwg/fetch#447 for options we are exploring for Fetch. It would be good if we could align on the exception to reject with and how to expose cancelation.

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Jan 25, 2017

Contributor

Great, thanks Anne. We'll wait to see what you come up with there.

Contributor

birtles commented Jan 25, 2017

Great, thanks Anne. We'll wait to see what you come up with there.

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Jan 25, 2017

It's almost certainly going to be "reject with AbortError" - is that fair to say @annevk?

It's almost certainly going to be "reject with AbortError" - is that fair to say @annevk?

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Jan 25, 2017

Member

I think that's reasonable, though if we want reusable code with Node.js we might want to consider actually minting a non-DOMException for this. Also, I suspect they're interested in the pattern for aborting itself too?

Member

annevk commented Jan 25, 2017

I think that's reasonable, though if we want reusable code with Node.js we might want to consider actually minting a non-DOMException for this. Also, I suspect they're interested in the pattern for aborting itself too?

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Aug 23, 2017

Contributor

@jakearchibald @annevk How should we approach unsettled promises on canceled animations now (in light of Fetch having worked out what to do there). Is "reject with AbortError" (i.e. currently specced behavior) still ok?

Contributor

birtles commented Aug 23, 2017

@jakearchibald @annevk How should we approach unsettled promises on canceled animations now (in light of Fetch having worked out what to do there). Is "reject with AbortError" (i.e. currently specced behavior) still ok?

@jakearchibald

This comment has been minimized.

Show comment
Hide comment
@jakearchibald

jakearchibald Aug 23, 2017

Yeah, after all that, what you already had turned out to be the standard. It's not the best solution we could have had, but it's the one we have 😀

Yeah, after all that, what you already had turned out to be the standard. It's not the best solution we could have had, but it's the one we have 😀

@birtles

This comment has been minimized.

Show comment
Hide comment
@birtles

birtles Aug 23, 2017

Contributor

No problem. Thanks for the quick response!

Contributor

birtles commented Aug 23, 2017

No problem. Thanks for the quick response!

@birtles birtles closed this in a483117 Aug 23, 2017

webanimbot pushed a commit that referenced this issue Aug 23, 2017

Drop issues about the possibility of cancelable promises
According to #141 these are not going to eventuate after all.

This closes #141.

Generated from:

commit a483117
Author: Brian Birtles <birtles@gmail.com>
Date:   Wed Aug 23 14:54:40 2017 +0900

    Drop issues about the possibility of cancelable promises

    According to #141 these are not going to eventuate after all.

    This closes #141.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.