Hello Robbie, neat trick. Does the promise that is never resolved or rejected get cleaned up (garbage collected), or does it stick around and leak memory?
Even if we're done with the component, will the engine be hanging on to each then handler waiting indefinitely to call setUser, which never happens?
One way to test this would be to re-render a component that uses this tool many times by incrementing a key prop on it like 100,000 times, and seeing if memory growth is garbage collected in Chrome Devtool's Performance tab.
What I do to ensure my Promises are cleaned up (so that dependent then or catch handlers aren't waiting indefinitely) is to reject them with a special error that I look out for in a catch, an error like class Cancellation extends Error, and when I reject the promise with that error the dependent then/catch handlers know the promise is settled (resolved or rejected) and in the case they receive a Cancellation rejection then they don't handle that error (or do something like onCancel), and otherwise handle other types of errors like regular errors.
Hi Joe, thank you for your comment and good point! I have not tested it but did some more research and I think you're probably right about the memory leak. There is also a discussion in a React issue on Github relevant to this. Maybe this can be a solution?
Hey, sorry for the late reply! That TrashablePromise implementation can still leak the promises if they never settle (same with the ideas mentioned in that GitHub issue). The only way to cancel a promise, is to reject it. But if we receive a promise and it is out of our control as to whether we can make it settle, then that TrashablePromise idea (or CancelablePromise from that GitHub issue) is the next best option, and in that case we can only hope the externally provided Promise will sometime settle.
Regarding the Fetch API, it has an Abort API which we can take advantage of to cancel the network operation, and we should make sure to reject any promises that we may have handed to any other code. It is expected that any other code handling promises should handle rejections (with .catch or try-catch). I think this is often overlooked. I have a lint rule in my project that throws an error on any code that doesn't handle promise rejection.
The downstream code can check the error to see if it is a special type of error that signifies cancellation. This is all up to the promise author to implement and document as part of their API documentation.
It would be neat if there was something higher level, but even if there was, ultimately the end developer would still need to explicitly stop async operations. I think this isn't as well-known as it should be, at least it seems to be an edge case that devs forget to handle until it becomes a problem (we are human after all 😃).
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Hello Robbie, neat trick. Does the promise that is never resolved or rejected get cleaned up (garbage collected), or does it stick around and leak memory?
Even if we're done with the component, will the engine be hanging on to each
then
handler waiting indefinitely to callsetUser
, which never happens?One way to test this would be to re-render a component that uses this tool many times by incrementing a
key
prop on it like 100,000 times, and seeing if memory growth is garbage collected in Chrome Devtool's Performance tab.What I do to ensure my Promises are cleaned up (so that dependent
then
orcatch
handlers aren't waiting indefinitely) is to reject them with a special error that I look out for in acatch
, an error likeclass Cancellation extends Error
, and when I reject the promise with that error the dependent then/catch handlers know the promise is settled (resolved or rejected) and in the case they receive a Cancellation rejection then they don't handle that error (or do something likeonCancel
), and otherwise handle other types of errors like regular errors.Hi Joe, thank you for your comment and good point! I have not tested it but did some more research and I think you're probably right about the memory leak. There is also a discussion in a React issue on Github relevant to this. Maybe this can be a solution?
Hey, sorry for the late reply! That TrashablePromise implementation can still leak the promises if they never settle (same with the ideas mentioned in that GitHub issue). The only way to cancel a promise, is to reject it. But if we receive a promise and it is out of our control as to whether we can make it settle, then that TrashablePromise idea (or CancelablePromise from that GitHub issue) is the next best option, and in that case we can only hope the externally provided Promise will sometime settle.
Regarding the Fetch API, it has an Abort API which we can take advantage of to cancel the network operation, and we should make sure to reject any promises that we may have handed to any other code. It is expected that any other code handling promises should handle rejections (with
.catch
ortry-catch
). I think this is often overlooked. I have a lint rule in my project that throws an error on any code that doesn't handle promise rejection.The downstream code can check the error to see if it is a special type of error that signifies cancellation. This is all up to the promise author to implement and document as part of their API documentation.
It would be neat if there was something higher level, but even if there was, ultimately the end developer would still need to explicitly stop async operations. I think this isn't as well-known as it should be, at least it seems to be an edge case that devs forget to handle until it becomes a problem (we are human after all 😃).