Skip to content

Instantly share code, notes, and snippets.

@samthor
Last active July 18, 2022 11:02
Show Gist options
  • Save samthor/8f72127e3cf44bca1fc6527ce7e47023 to your computer and use it in GitHub Desktop.
Save samthor/8f72127e3cf44bca1fc6527ce7e47023 to your computer and use it in GitHub Desktop.
Async cancellable promises
// nb. This code is available in an ES module of Promise helpers, here:
// https://github.com/samthor/promises
// symbol returned to indicate that a call was cancelled
export const takeoverSymbol = Symbol('takeover');
/**
* Accepts a generator function, which yields Promises, and converts it to an async function
* that cancels any previous calls.
*/
export function makeSingle(generator) {
let globalNonce;
return async function(...args) {
const localNonce = globalNonce = new Object();
const iter = generator(...args);
let resumeValue;
for (;;) {
const n = iter.next(resumeValue);
if (n.done) {
return n.value; // final return value of passed generator
}
// whatever the generator yielded, _now_ run await on it
resumeValue = await n.value;
if (localNonce !== globalNonce) {
return takeoverSymbol; // a new call was made
}
// next loop, we give resumeValue back to the generator
}
};
}
/**
* Demonstration function which fetches something, updates the DOM, and calls
* something else after 5s. This is a generator, so we can make it cancellable,
* and it yields its Promises to the caller.
*/
function* fetchAndFlash(page) {
const response = yield fetch('/api/info?p=' + page);
const json = yield response.json();
infoNode.innerHTML = json.html;
yield new Promise((resolve) => setTimeout(resolve, 5000));
flashForAttention(infoNode);
}
import {makeSignal} from './code.js'; // maybe you want to use this via a different import approach?
// convert this to an async function that only runs once
fetchAndFlash = makeSingle(fetchAndFlash);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment