Skip to content

Instantly share code, notes, and snippets.

@eduardolundgren
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save eduardolundgren/9785720 to your computer and use it in GitHub Desktop.
Save eduardolundgren/9785720 to your computer and use it in GitHub Desktop.
CancellablePromise.all
/**
* Cancellable promise.
*
* @class CancellablePromise
* @constructor
* @extends {Promise}
* @param {Function} fn A function where to insert the logic that resolves this
* promise. Receives `fulfill` and `reject` functions as parameters. This
* function is called synchronously.
* @param {Function} opt_errorCallback Optional error callback to be fired
* whenever a cancellable promise is cancelled.
*/
function CancellablePromise(fn, opt_errorCallback) {
CancellablePromise.superclass.constructor.apply(this, arguments);
this._errorCallback = opt_errorCallback;
}
A.extend(CancellablePromise, A.Promise, {
/**
* Cancels the Promise by rejecting it with a cancel Error. No action is
* performed if the Promise is already resolved.
*
* @method cancel
* @param {String} opt_message An optional debugging message for describing
* the cancellation reason.
*/
cancel: function(opt_message) {
var error = new A.CancellablePromise.Error(opt_message);
try {
if (this._errorCallback) {
this._errorCallback(error);
}
}
catch (e) {
this._resolver.reject(e);
return;
}
this._resolver.reject(error);
},
then: function() {
var instance = this,
promise = CancellablePromise.superclass.then.apply(this, arguments);
promise.cancel = A.bind(instance.cancel, instance);
return promise;
}
});
/*
* Returns a cancellable promise that is resolved or rejected when all values
* are resolved or any is rejected. This is useful for waiting for the
* resolution of multiple promises, such as reading multiple files in Node.js or
* making multiple XHR requests in the browser.
*
* @method all
* @param {Any[]} values An array of any kind of values, promises or not. If a
* value is not
* @return {CancellablePromise} A promise for an array of all the fulfillment values
* @static
*/
CancellablePromise.all = function(values) {
var CancellablePromise = this,
children = [];
return new CancellablePromise(function(resolve, reject) {
if (!A.Lang.isArray(values)) {
reject(new TypeError('CancellablePromise.all expects an array of values or promises'));
return;
}
var remaining = values.length,
i = 0,
length = values.length,
results = [],
child;
function oneDone(index) {
return function(value) {
results[index] = value;
remaining--;
if (!remaining) {
resolve(results);
}
};
}
if (length < 1) {
return resolve(results);
}
for (; i < length; i++) {
child = CancellablePromise.resolve(values[i]);
child.then(oneDone(i), reject);
children.push(child);
}
}).then(function(result) {
children = null;
return result;
},
function(reason) {
A.Array.invoke(children, 'cancel');
children = null;
throw reason;
});
};
/*
* Ensures that a certain value is a cancellable promise. If it is not a
* promise, it wraps it in one.
*
* @method resolve
* @param {Any} Any object that may or may not be a promise
* @return {CancellablePromise}
* @static
*/
CancellablePromise.resolve = A.Promise.resolve;
/*
* A shorthand for creating a rejected cancellable promise.
*
* @method reject
* @param {Any} reason Reason for the rejection of this promise. Usually an
* Error Object
* @return {CancellablePromise} A rejected promise
* @static
*/
CancellablePromise.reject = A.Promise.reject;
A.CancellablePromise = CancellablePromise;
/**
* Error used as a rejection reason for canceled Promises.
*
* @class Promise.CancellationError
* @constructor
* @extends {Error}
* @param {String} opt_message An optional debugging message for describing the
* cancellation reason.
*/
function CancellationError(opt_message) {
CancellationError.superclass.constructor.apply(this, arguments);
this.message = opt_message;
}
A.extend(CancellationError, Error, {
name: 'cancel'
});
A.CancellablePromise.Error = CancellationError;
var delay = function(ms) {
var timeout;
return new Y.CancellablePromise(
function(resolve) {
timeout = setTimeout(function() {
resolve();
}, ms);
},
function() {
clearTimeout(timeout);
console.log('Delay cancelled by a CancellationError.');
}
);
};
var all = Y.CancellablePromise.all([delay(3000), delay(4000)]).then(
function() {
console.log('Y.CancellablePromise.all done');
},
function(reason) {
console.log('Y.CancellablePromise.all rejectd', reason);
throw reason;
});
all.cancel();
var delay = function(ms) {
var timeout;
return new Y.CancellablePromise(function(resolve) {
timeout = setTimeout(function() {
resolve();
}, ms);
})
.then(
function() {
console.log('delay done');
},
function(reason) {
if (reason instanceof Y.CancellablePromise.Error) {
clearTimeout(timeout);
console.log('Delay cancelled by a CancellationError.');
}
throw reason;
}
);
};
var all = Y.CancellablePromise.all([delay(3000), delay(4000)]).then(
function() {
console.log('Y.CancellablePromise.all done');
},
function(reason) {
console.log('Y.CancellablePromise.all rejectd', reason);
throw reason;
});
all.cancel();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment