Git Product home page Git Product logo

Comments (8)

jonschlinkert avatar jonschlinkert commented on July 1, 2024 2

I think the following example demonstrates the same issue (please correct me if I'm wrong):

const promise = new pCancelable((resolve, reject, onCancel) => {
  const timeout = setTimeout(() => {
    resolve(true);
  }, 1000);

  onCancel.shouldReject(true);
  onCancel(() => {
    clearTimeout(timeout);
    resolve(false);
  });
});

promise.shouldReject = true;
promise.cancel();
promise
  .then(value => console.log(value))
  .catch(console.error);

Essentially, since resolve() is called inside the onCancel() function, the cancellation never occurs, despite .cancel() being called before the promise actually resolving.

I think we can fix this by changing the following code:

p-cancelable/index.js

Lines 44 to 50 in 9fa975b

const onCancel = handler => {
if (!this._isPending) {
throw new Error('The `onCancel` handler was attached after the promise settled.');
}
this._cancelHandlers.push(handler);
};

To something like this:

const onCancel = handler => {
  if (!this._isPending) {
    throw new Error('The `onCancel` handler was attached after the promise settled.');
  }
  
  // we need to wrap the handler to set `_isCancelled` before
  // the handler function is actually invoked
  const fn = (...args) => {
    this._isCanceled = true;
    handler(...args);
  };

  this._cancelHandlers.push(fn);
};

And we would change the following:

p-cancelable/index.js

Lines 34 to 37 in 9fa975b

const onResolve = value => {
this._isPending = false;
resolve(value);
};

To something like:

const onResolve = value => {
  // if the promise was already cancelled, we can stop
  if (!this._isCanceled) {
    this._isPending = false;
    resolve(value);
  }
};

If this seems like an acceptable approach and it solves the problem being described, I'd be happy to do a PR.

from p-cancelable.

armandabric avatar armandabric commented on July 1, 2024 1

Hi @szmarczak, you are defining the onCancel in the setTimeout, so when you do cancelable.cancel(); it is not yet executed. Move the call outside the setTimeout to make it works:

const PCancelable = require('p-cancelable');
const cancelable = new PCancelable((resolve, reject, onCancel) => {
	onCancel(() => console.log('Cancelled')); // It will be called

	setTimeout(() => {
        	console.log('Timeout');
	}, 1000);
});

cancelable.catch(() => {});
cancelable.cancel();

from p-cancelable.

fregante avatar fregante commented on July 1, 2024 1

It took me a bit to understand this too.

This is akin to adding an event listener after the event was fired, e.g.

document.click();
document.addEventListener('click', console.log);

Now in p-cancelable terms:

p.cancel();
...
onCancel(console.log);

I think this could be achieved by treating onCancel callbacks as .then callbacks of a private Promise, instead of manually creating an array (_cancelHandlers) and calling them with a loop.

from p-cancelable.

fregante avatar fregante commented on July 1, 2024 1

However, a failing onCancel callback currently throws its own error:

p-cancelable/index.js

Lines 77 to 89 in 8746e2a

if (this._cancelHandlers.length > 0) {
try {
for (const handler of this._cancelHandlers) {
handler();
}
} catch (error) {
this._reject(error);
}
}
this._isCanceled = true;
if (this._rejectOnCancel) {
this._reject(new CancelError(reason));

And if said onCancel callback is called after (as requested by this issue), it will no longer change the error, so the behavior would be different depending on when onCancel is called.

from p-cancelable.

sindresorhus avatar sindresorhus commented on July 1, 2024

What do you mean by "cancelled already"? Can you provide an example of what's not working as expected?

The onCancel handlers are called synchronously when use call .cancel():

p-cancelable/index.js

Lines 72 to 85 in 354c400

cancel(reason) {
if (!this._isPending || this._isCanceled) {
return;
}
if (this._cancelHandlers.length > 0) {
try {
for (const handler of this._cancelHandlers) {
handler();
}
} catch (error) {
this._reject(error);
}
}

from p-cancelable.

szmarczak avatar szmarczak commented on July 1, 2024

Sorry, here's the example:

const PCancelable = require('p-cancelable');
const cancelable = new PCancelable((resolve, reject, onCancel) => {
	setTimeout(() => {
        console.log('Timeout');
		onCancel(() => console.log('Cancelled')); // Should this be called?
	}, 1000);
});

cancelable.catch(() => {});
cancelable.cancel();

from p-cancelable.

szmarczak avatar szmarczak commented on July 1, 2024

@Spy-Seth IKR. This is not what I want. What I am trying to show, is that if onCancel callback should be called if the promise was cancelled already.

from p-cancelable.

sindresorhus avatar sindresorhus commented on July 1, 2024

@jonschlinkert Sounds good. PR welcome 👍

from p-cancelable.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.