Git Product home page Git Product logo

p-cancelable's Issues

Polyfill ?

Can this become a polyfill extends the current Promise class that I can get a cancelable Promise whenever and whereever in my app?

Convert abortable Promise-returning functions to cancelable promises

Common Promises don't have a .cancel method, you have to create an AbortSignal, maybe one for each, and keep track of them. Then if you want to abort multiple promises at once you have to keep this variable around somehow.

What if p-cancelable or similar could just handle that?

const cancelable = new PCancelable(signal => fetch('/api', {signal}))

This would be a good companion to sindresorhus/p-race#4

React-Native: Error on module init

In a react-native environment (0.57.5) on module import the following error is thrown and causes the app to crash: TypeError: undefined is not a function (evaluating Object.setPrototypeOf(PCancelable.prototype,Promise.prototype)')

If you change the inheritence to ES6 style (PCancelable extends Promise) the error is gone.

Support wrapping an existing promise

Hi,

Using the fn function feels a bit unnatural and it was not obvious at first glance how to do what I wanted. Once I understood it was ok.

Would you be ok to support a new constructor that directly takes a promise? It is a quite common usecase

Before

const validateDateRangePromise = PCancelable.fn(() => {
  return validateDateRange(dateRange);
})();

or

const validateDateRangePromise = PCancelable.fn(validateDateRange)(dateRange);

After

const validateDateRangePromise = PCancelable.fromPromise(validateDateRange(dateRange));

isCanceled is not set to true when shouldReject is set to false and promise is rejected in onCancel

I'm doing some p-cancelable testing to get familiar with it and I noticed that isCanceled is not set to true on the promise when the promise is canceled with shouldReject set to false.

I briefly took a look at the library code but TBH I don't see any reason for this to happen so reporting this issue.

My code is (I know, ugly but as said it is my test code):

import PCancelable from 'p-cancelable';

const cancelablePromise = doJob();

try {
    await sleep(500);

    cancelablePromise.cancel();
}
catch (error) {
    console.log("First main catch error: " + error);
}

try {
    const result = await cancelablePromise;
    console.log("result", result);
} catch (error) {
    console.log("Second main catch error: " + error);

    if (cancelablePromise.isCanceled)
        console.log("Don't worry it was canceled")
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

function doJob() {
    return new PCancelable((resolve, reject, onCancel) => {
        try {
            const timeout = setTimeout(() => {
                const result = job();
                resolve(result);
            }, 1000);

            onCancel.shouldReject = false;

            onCancel(() => {
                console.log('canceled');
                clearTimeout(timeout);
                reject(new Error('canceled'));
            });
        }
        catch (error) {
            console.log('Promise catch error: ' + error);
            reject(error);
        }
    });
}

Current behavior:

> node .\index.js
canceled
Second main catch error: Error: canceled

Expected behavior:

> node .\index.js
canceled
Second main catch error: CancelError: Promise was canceled
Don't worry it was canceled

If I remove onCancel.shouldReject = false; then it is fine.

About `AbortController`

The readme says the following:

image

However, the AbortController interface is primarily targeted at web requests, and since p-cancelable is useful for a lot more than web requests, it might be worth clarifying that in the readme.

How to use this with p-lazy?

I want a Promise that is cancelable and whose executor is lazily evaluated. Is this possible by composing p-cancelable with p-lazy?

At the moment it seems impossible. If I wrap p-lazy with p-cancelable...

const cancelable = new PCancelable((outerResolve, outerReject, onCancel) => {
  const lazy = new PLazy((innerResolve, innerReject) => {
    // Our executor logic goes here
    // use innerResolve, innerReject, onCancel
  })
  lazy.then(outerResolve, outerReject) // Oops
})

...it would no longer be lazy, because calling lazy.then() triggers the executor. On the other hand, if I wrap p-cancelable with p-lazy...

const lazy = new PLazy((outerResolve, outerReject) => {
  const cancelable = new PCancelable((innerResolve, innerReject, onCancel) => {
    // Our executor logic goes here
    // use innerResolve, innerReject, onCancel
  })
  cancelable.then(outerResolve, outerReject)
})

...then we cannot cancel it because lazy does not have a .cancel() method.

TypeScript types don't work for calling .then on a PCancelable promise

I would expect something like the following to typecheck, but it doesn't:

let promise: PCancelable<void> = (new PCancelable((resolve, reject, onCancel) => {
  setTimeout(() => resolve());
})).then(() => console.log("Then function called"));

When I try to do something like this, I get the type error

Type 'Promise<void>' is not assignable to type 'PCancelable<void>'.
  Property 'isCanceled' is missing in type 'Promise<void>'. [2322]

Calling .then on a PCancelable to get a new PCancelable is something that should work, right? I think the reason it's not working is because the type declaration in index.d.ts doesn't override the next (or catch) methods when extending Promise:

declare class PCancelable<ValueType> extends Promise<ValueType> { ... }

Not compatible with global Bluebird promises

This library, and therefore got, can't be used in a program that uses Bluebird promises globally. This is because PCancelable amends its prototype tree to make it a subclass of Promise but never calls the base Promise constructor, making it a false subclass.

The following code demonstrates this:

import Bluebird from 'bluebird';
global.Promise = Bluebird;

import pcancelable from 'p-cancelable';

async function run() {
  return await new pcancelable((resolve, reject) => {
    resolve(true);
  });
}

run().then(_ => console.log(_));

The code produces no output. It should print true.

Passing cancellation reason to cancel handler

Does it make sense to pass the cancellation reason to the registered cancel handlers, like this:

const promise = new PCancelable((resolve, reject, onCancel) => {
    onCancel(reason => {
        console.log(reason); // <= should print 'foo'
    });
});

promise.cancel('foo');

If it does, I'll make a PR.

【Discussion】Object.setPrototypeOf(PCancelable.prototype, Promise.prototype)

in devdocs: https://devdocs.io/javascript/global_objects/object/setprototypeof

It warns that

Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, currently a very slow operation in every browser and JavaScript engine. In addition, the effects of altering inheritance are subtle and far-flung, and are not limited to the time spent in the Object.setPrototypeOf(...) statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. You can read more in JavaScript engine fundamentals: optimizing prototypes.

I am puzzled about the usage of setPrototypeOf with PCancelable.prototype. whether it is a bad practice as warnned?

I think not because it doesn't change the promise.prototype in runtime

how about the following code? we usually need to proxy the original functions and add some logic ourselves

const originalCatch = Promise.prototype.catch;
Promise.prototype.catch = (reject) => {
	console.log("my catch");
	return originalCatch(reject);
};

Utility static function to convert executor into a PCancelable

Could be very helpful to have a static method like PCancelable.makeCancelable to convert a method into a PCancelable.

export function makeCancellable<T>(executor: (onCancel: OnCancelFunction) => T | PromiseLike<T>): PCancelable<T> {
    return new PCancelable<T>(
        async (resolve, reject, onCancel) => {
            try {
                resolve(await executor(onCancel));
            } catch (error) {
                reject(error);
            }
        }
    );
}

export function foo() {
    return makeCancellable(_foo);
}

async function _foo(onCancel: OnCancelFunction) {
    // some async action here ...
}

export function goo() {
    return makeCancellable(
        onCancel => {
            // some action here ...
        }
    )
}

Decorator

Would be useful to expose a decorator when the Decorator proposal is more stable.

I'm thinking something like:

class Unicorn {
	@cancelable
	async rainbow(onCancel, input) {}
}

Just opening this issue so I won't forget. Not something worth doing yet.

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.