Skip to content

Commit

Permalink
✨ Allow Pledge instances to be cancelled
Browse files Browse the repository at this point in the history
  • Loading branch information
skerit committed Feb 17, 2024
1 parent acf0c03 commit 4c0f11a
Show file tree
Hide file tree
Showing 3 changed files with 301 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## 0.9.0 (WIP)

* Rewrite JavaScript tokenizer to no longer use regexes
* Allow `Pledge` instances to be cancelled

## 0.9.0 (2024-02-15)

Expand Down
154 changes: 138 additions & 16 deletions lib/pledge.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
const PENDING = 0,
RESOLVED = 1,
REJECTED = 2;
REJECTED = 2,
CANCELLED = 3;

const REJECTED_REASON = Symbol('rejected_reason'),
RESOLVED_VALUE = Symbol('resolved_value'),
START_EXECUTOR = Symbol('start_executor'),
ON_FULFILLED = Symbol('on_fulfilled'),
SUB_PLEDGES = Symbol('sub_pledges'),
ON_CANCELLED = Symbol('on_cancelled'),
SUB_PLEDGES = Symbol('sub_pledges'),
ON_REJECTED = Symbol('on_rejected'),
DO_RESOLVE = Symbol('do_resolve'),
ON_FINALLY = Symbol('on_finally'),
DO_FINALLY = Symbol('do_finally'),
DO_REJECT = Symbol('do_reject'),
EXECUTOR = Symbol('executor'),
UPDATED = Symbol('updated'),
Expand Down Expand Up @@ -92,6 +96,15 @@ AbstractPledge.setProperty({
*/
[ON_REJECTED]: null,

/**
* An array of tasks to perform when this pledge is cancelled
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
[ON_CANCELLED]: null,

/**
* The eventual resolved value
*
Expand Down Expand Up @@ -132,17 +145,6 @@ AbstractPledge.setProperty({
*/
_durations: null,

/**
* Property that could be a function to cancel the pledge
*
* @author Jelle De Loecker <[email protected]>
* @since 0.7.0
* @version 0.7.0
*
* @type {Function}
*/
cancel: null,

/**
* Warn when an error is not caught
*
Expand Down Expand Up @@ -519,6 +521,111 @@ AbstractPledge.setMethod(function reportProgressPart(parts) {});
*/
AbstractPledge.setMethod(function _addProgressPledge(pledge) {});

/**
* Cancel the pledge
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(function cancel() {

if (!this.isPending()) {
return;
}

this[STATE] = CANCELLED;

// Always do the on-cancel tasks as swiftly as possible
return Swift.all(this[ON_CANCELLED]).finally(() => this[DO_FINALLY]());
});

/**
* Do the given task when this pledge is cancelled
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(function onCancelled(task) {

if (typeof task != 'function') {
return;
}

if (!this.isPending()) {

if (this.isCancelled() && task) {
task();
}

return;
}

if (!this[ON_CANCELLED]) {
this[ON_CANCELLED] = [];
}

this[ON_CANCELLED].push(next => Swift.done(task(), next));
});

/**
* Do all the finally callbacks
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(DO_FINALLY, function doFinally() {
while (this[ON_FINALLY]?.length) {
this[ON_FINALLY].shift()();
}
});

/**
* Has this pledge been resolved?
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(function isResolved() {
return this[STATE] === RESOLVED;
});

/**
* Has this pledge been rejected?
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(function isRejected() {
return this[STATE] === REJECTED;
});

/**
* Has this pledge been cancelled?
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(function isCancelled() {
return this[STATE] === CANCELLED;
});

/**
* Is this pledge still pending?
*
* @author Jelle De Loecker <[email protected]>
* @since 0.9.1
* @version 0.9.1
*/
AbstractPledge.setMethod(function isPending() {
return this[STATE] === PENDING;
});

/**
* The BasePledge Class
*
Expand Down Expand Up @@ -1075,15 +1182,28 @@ Pledge.setMethod('catch', function _catch(on_rejected) {
*
* @author Jelle De Loecker <[email protected]>
* @since 0.5.6
* @version 0.5.6
* @version 0.9.1
*
* @param {Function} on_finally
*
* @return {Pledge}
*/
Pledge.setMethod('finally', function _finally(on_finally) {

var constructor = this.constructor;
let constructor = this.constructor;

if (this.isPending() || this.isCancelled()) {
if (!this[ON_FINALLY]) {
this[ON_FINALLY] = [];
}

// We keep this in an array in case the pledge gets cancelled
this[ON_FINALLY].push(on_finally);

if (this.isCancelled()) {
return this[DO_FINALLY]();
}
}

return this.then(
function afterResolved(value) {
Expand Down Expand Up @@ -1374,8 +1494,9 @@ Swift.setMethod(DO_RESOLVE, function _doResolve(value) {

this[ON_REJECTED].length = 0;
}
});

this[DO_FINALLY]();
});

/**
* Reject with the given reason
Expand All @@ -1393,6 +1514,7 @@ Swift.setMethod(function reject(reason) {
}

this[DO_REJECT](reason);
this[DO_FINALLY]();
});

/**
Expand Down
Loading

0 comments on commit 4c0f11a

Please sign in to comment.