Last active
July 18, 2022 11:02
-
-
Save samthor/8f72127e3cf44bca1fc6527ce7e47023 to your computer and use it in GitHub Desktop.
Async cancellable promises
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
} | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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