DEV Community

Discussion on: Cancel fetch requests, and a way to abstract it

Collapse
 
jcubic profile image
Jakub T. Jankiewicz • Edited

Yes, just use new CustomPromise and pass the result of then into that new promise.

This is the implementation of promise wrapper in my project (I still have part of the code using prototypes).

    function QuotedPromise(promise) {
        var internal = {
            pending: true,
            rejected: false,
            fulfilled: false,
            reason: undefined,
            type: undefined
        };
        // then added to __promise__ is needed otherwise rejection
        // will give UnhandledPromiseRejectionWarning in Node.js
        promise = promise.then(v => {
            internal.type = type(v);
            internal.fulfilled = true;
            internal.pending = false;
            return v;
        });
        // promise without catch, used for valueOf - for rejecting
        // that should throw an error when used with await
        read_only(this, '_promise', promise, { hidden: true });
        if (is_function(promise.catch)) {
            // prevent exception on unhandled rejecting when using
            // '>(Promise.reject (new Error "zonk")) in REPL
            promise = promise.catch((err) => {
                internal.rejected = true;
                internal.pending = false;
                internal.reason = err;
            });
        }
        Object.keys(internal).forEach(name => {
            Object.defineProperty(this, `__${name}__`, {
                enumerable: true,
                get: () => internal[name]
            });
        });
        read_only(this, '__promise__', promise);
        // prevent resolving when returned from real promise #153
        this.then = false;
    }
    // ----------------------------------------------------------------------
    QuotedPromise.prototype.then = function(fn) {
        return new QuotedPromise(this.valueOf().then(fn));
    };
    // ----------------------------------------------------------------------
    QuotedPromise.prototype.catch = function(fn) {
        return new QuotedPromise(this.valueOf().catch(fn));
    };
    // ----------------------------------------------------------------------
    QuotedPromise.prototype.valueOf = function() {
        if (!this._promise) {
            throw new Error('QuotedPromise: invalid promise created');
        }
        return this._promise;
    };
    // ----------------------------------------------------------------------
    QuotedPromise.prototype.toString = function() {
        if (this.__pending__) {
            return QuotedPromise.pending_str;
        }
        if (this.__rejected__) {
            return QuotedPromise.rejected_str;
        }
        return `#<js-promise resolved (${this.__type__})>`;
    };
    QuotedPromise.pending_str = '#<js-promise (pending)>';
    QuotedPromise.rejected_str = '#<js-promise (rejected)>';
Enter fullscreen mode Exit fullscreen mode

The pattern is very similar to Monads (in fact some explanaions shows promises as example of modals) and Monad should never mutate the data.

Thread Thread
 
nombrekeff profile image
Keff

Nice, yes I ended up solving it like this:

class CustomRequest {
    then(fn) {
        return new CustomRequest(
            this.promise.then(fn),
            this.abortController,
        );
    }

    catch(fn) {
        return new CustomRequest(
            this.promise.catch(fn),
            this.abortController,
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Though not complete, it does the job and could be improved as the needs arise.

Thanks again for pointing this out, I've made an edit in the post to explain to future readers.

Thread Thread
 
nombrekeff profile image
Keff

The pattern is very similar to Monads (in fact some explanaions shows promises as example of modals) and Monad should never mutate the data.

Ohh cool, never thought of promises as monads, makes sense