1

I have a React component that takes a visible bool prop. The react executes a function which triggers a long running Promise, and I need to cancel out of the Promise when visible changes. Trying to externally reject the Promise does not stop the execution however.

A rough outline of the code would look like:

<ComponentA visible={visible} />
const ComponentA = ({ visible }) => {
   const [rejectFn, setRejectFn] = useState(() = () => console.log('test');

    useEffect(() => {
        if (visible) {
            ...
        } else {
            setRejectFn();
        }
    }, [visible]);

   const promiseFn = () => (
       new Promise((resolve, reject) => {
            // logic

            const endCallback = (error) => {
                if (error) {
                    reject(error);
                    console.log('error', error);
                } else {
                    resolve(...);
                }
            };

            setRejectFn(() = () => endCallback('exit early'));

            someOtherFn(..., endCallback); // processing file chunk by chunk
       })
   );

   const onDivClick = () => (
      // set some state vars
      promiseFn()
          .then(() => ...)
          .catch(() => ...)
          .finally(() => ...);
   );

   return (
      <div onClick=(onDivClick) />
   );
}

The above code will fire off the rejectFn and log "exit early", however the Promise will continue to execute until completion.

Arthur
  • 2,622
  • 4
  • 28
  • 46
  • Does this answer your question? [Promise - is it possible to force cancel a promise](https://stackoverflow.com/questions/30233302/promise-is-it-possible-to-force-cancel-a-promise) – user120242 Jun 03 '20 at 03:27
  • By design Promises are guaranteed to always resolve (or error out). You can simulate cancellation by no-oping, but it is supposed to always resolve by design. – user120242 Jun 03 '20 at 03:28
  • Your code also doesn't clean up the Promise on re-render, which could cause duplicate calls and Promises to resolve. – user120242 Jun 03 '20 at 03:38
  • Why don't you tell a bit more about this long running code? If it is some computation, you would need to check inside that computation wether the Promise had been "cancelled" and stop computing. Like `return` or `throw` whatever the fastest way out is. – Thomas Jun 03 '20 at 08:13
  • @Thomas the long running code is basically this: https://stackoverflow.com/a/39112502/4781945 – Arthur Jun 03 '20 at 16:49

1 Answers1

2

Here you go :

You can't cancel the ongoing promise request, but you can do something like this

  const visibleRef = useRef(visible); // using ref to get latest value inside setInterval

  useEffect(() => {
    visibleRef.current = visible;
    console.log("visible", visible);
  }, [visible]); // <--- Set the value of visible whenever it changes

  const promiseFn = () =>
    new Promise((resolve, reject) => {
      // logic

      // Will check visibleRef.current every second , you can reduce the time as your need
      const interval = setInterval(() => {
        if (!visibleRef.current) { 
          reject("Due to Visible false value");
          clearInterval(interval);
        }
      }, 1000); 

      // just to mock the promise event execution
      setTimeout(() => {
        resolve();
        clearInterval(interval);
      }, 5000);
    });

WORKING DEMO

Please check the console, that will help you to get demo's understanding

Edit #SO-Promise-cancel-issue

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • Your demo is not really relevant to the topic, you can easy cancel the "long running task" because you are using `setTimeout`, but `someOtherFn(..., endCallback);` is some thing more complicated that is mentioned in the topic comments: https://stackoverflow.com/questions/39112096/calculate-md5-hash-of-a-large-file-using-javascript/39112502#39112502 – Tony Nguyen Jun 05 '20 at 16:41
  • Thanks for commenting, I have used the set time out just to mock process for same as someotherfn , you can stop those by checking visible I have used inside using ref. – Vivek Doshi Jun 05 '20 at 17:06
  • If there is no way to cancel `someOtherFn(..., endCallback);` the demo won't give any value. It's better to check the comments of topic where more clarifications of topic is define. – Tony Nguyen Jun 05 '20 at 17:34
  • I think you should check demo, click on make promise request that will take 5 secs to complete if before that you toggle the visible it will cause the promise to reject, and that is my understanding via question, read the first para of question, and if this not that OP wants ,I will happily remove my answer :) – Vivek Doshi Jun 05 '20 at 17:52