all files / modules/utils/ AbortablePromise.js

64.71% Statements 22/34
50% Branches 5/10
75% Functions 6/8
64.71% Lines 22/34
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                                                                                                                                          
const Promise = require("bluebird");
const R = require("ramda");
 
function makeAbortable(promise, abort) {
    promise.abort = abort;
 
  // Hijack promise.then so it returns an abortable promise.
    const _then = promise.then;
    promise.then = function () {
        return makeAbortable(_then.apply(promise, arguments), abort);
    };
 
    return promise;
}
 
/**
 * A Promise class with an abort() method that calls the onAbort function
 * provided by the resolver.
 *
 * Example:
 *
 *   let promise = new AbortablePromise(function (resolve, reject, onAbort) {
 *     // Use resolve & reject as you normally would.
 *     let request = makeRequest( ... , function (error, response) {
 *       if (error) {
 *         reject(error);
 *       } else {
 *         resolve(response);
 *       }
 *     });
 *
 *     // Use onAbort to register a promise.abort() function. It is the
 *     // responsibility of this function to abort the execution of the
 *     // promise and resolve/reject as needed.
 *     onAbort(function () {
 *       request.abort();
 *       reject(new Error('Request was aborted'));
 *     });
 *   });
 *
 *   promise.abort(); // Calls the onAbort handler.
 */
function AbortablePromise(resolver) {
    Iif (!R.is(Function, resolver)) {
        throw new Error("AbortablePromise needs a resolver function");
    }
 
    let abort;
    const promise = new Promise(function (resolve, reject) {
        let aborter;
 
        abort = function () {
            if (R.isNil(aborter)) {
                return;
            }
 
            const fn = aborter;
            aborter = null;
 
            try {
                return fn.apply(this, arguments);
            } catch (error) {
                reject(error);
            }
        };
 
        resolver(function (child) {
            Iif (child && R.is(Function, child.abort)) {
                aborter = child.abort;
            } else {
                aborter = null;
            }
 
            resolve.apply(this, arguments);
        }, function () {
            aborter = null;
            reject.apply(this, arguments);
        }, function (fn) {
            Iif (!R.is(Function, fn)) {
                throw new Error("onAbort needs a function");
            }
 
            aborter = fn;
        });
    });
 
    return makeAbortable(promise, abort);
}
 
module.exports = AbortablePromise;