Skip to content

Instantly share code, notes, and snippets.

@bitifet
Last active September 12, 2019 08:39
Show Gist options
  • Save bitifet/28f126a11514ceff7b389cec7fe979eb to your computer and use it in GitHub Desktop.
Save bitifet/28f126a11514ceff7b389cec7fe979eb to your computer and use it in GitHub Desktop.
Promise Cancellator
// Promise cancellation utility
// Inspired on this @getify tweet:
// https://twitter.com/getify/status/1171820071582339072
// (Deferrable version)
// ----- IMPLEMENTATION: -----
function cancellator() {
let cancelTimowut = null;
let cancelMessage = "Cancelled";
const stoppers = [];
function stop({t0, reject}){
if (! cancelTimeout) {
reject(cancelMessage);
} else {
const now = Date.now();
const t = t0+cancelTimeout;
const remain = t - now;
if (remain <= 0) {
reject(cancelMessage);
} else {
setTimeout(()=>reject(cancelMessage), remain);
};
};
};
const API = {
control: p=>new Promise(function(resolve, reject) {
const stopper = {
t0: Date.now(),
reject,
};
if (cancelTimeout !== null) {
stop(stopper);
} else {
stoppers.push(stopper);
};
p.then(resolve, reject);
return API;
}),
abort(msg, timeout = 0) {
if (msg) cancelMessage = msg;
cancelTimeout = timeout;
stoppers.map(stop);
return API;
},
};
return API;
};
// ---------------------------
// --------- MOCKS: ----------
const sleep = t=>new Promise((rs)=>setTimeout(rs, t*1000));
const fetch = (url="??")=>sleep(Math.random()*5) // Fake fetch
.then(
()=>Math.round(Math.random())
? Promise.resolve('Ok: '+url)
: Promise.reject('Error: '+url)
)
;
// ---------------------------
// ------ ACTUAL CODE: -------
async function send(data, C=x=>x) {
try {
const res = await C(fetch(data));
console.log(res);
} catch (err) {
console.error("TROWN: " + err);
};
};
const onSend = (function(prevSend){
let c = 0; // Count button pushes
return function do_onSend(evt) {
prevSend.finally(async function(){
await send(++c
, cancellator().abort("CANCELLED!!: " +c, 2000).control
);
});
};
})(Promise.resolve());
// ---------------------------
// ------- SIMULATION: -------
async function randomPush() {
await sleep(Math.random()*3);
onSend();
return randomPush();
};
randomPush();
// ---------------------------
// Promise cancellation utility
// Inspired on this @getify tweet:
// https://twitter.com/getify/status/1171820071582339072
function cancellator() {
const stoppers = [];
return {
control: p=>new Promise(function(resolve, reject) {
stoppers.push(reject);
p.then(resolve, reject);
}),
abort: (msg)=>stoppers.map(s=>s(msg)),
};
};
// ------ EXAMPLE: ------- //
const sleep = t=>new Promise((r)=>setTimeout(r, t*1000));
async function doSomething(msg, C=x=>x) {
for (let i=1; i<=3; i++) {
await C(sleep(1));
console.log(`${msg} ${i}`);
};
};
doSomething("Uncancellable").catch(console.error);
const c = cancellator();
doSomething("Cancellable", c.control).catch(console.error);
sleep(2).then(()=>c.abort("Operation cancelled!!!"));
// ----------------------- //
// ------- OUTPUT: ------- //
// Uncancellable 1 //
// Cancellable 1 //
// Operation cancelled!!! //
// Uncancellable 2 //
// Uncancellable 3 //
// ----------------------- //
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment