Skip to content

Instantly share code, notes, and snippets.

@neborn
Last active April 11, 2021 00:47
Show Gist options
  • Save neborn/8460ae8ff0b47ccf978ad91da6df1592 to your computer and use it in GitHub Desktop.
Save neborn/8460ae8ff0b47ccf978ad91da6df1592 to your computer and use it in GitHub Desktop.
Use Task Hook
import {
useEffect,
useMemo
} from 'https://unpkg.com/htm@3.0.4/preact/standalone.module.js';
// Inspired by https://github.com/machty/ember-concurrency
export default function useTask(generator) {
const cancellable = useMemo(() => Cancellable.create(generator), [generator]);
useEffect(() => () => cancellable.cancel(), [cancellable]);
return [cancellable.perform.bind(cancellable)];
}
export function timeout(wait) {
return new Promise(resolve => setTimeout(resolve, wait));
}
class Cancellable {
static create(generator) {
return new Cancellable(generator);
}
constructor(generator) {
this._generator = generator;
this._isCanceled = false;
}
cancel() {
this._isCanceled = true;
}
perform(...args) {
this._perform(...args);
}
/**
* Splitting this in to a separate function to potentially support a better return value from public `perform`
*/
async _perform(...args) {
let gen = this._generator(...args);
let last = {};
let lastValue;
while(true) {
if (last.done) {
return lastValue;
}
if (this._isCanceled) {
gen.return();
// throw cancelled error?
return;
}
last = gen.next(lastValue);
// TODO only wait when the last value is a promise?
try {
lastValue = await last.value;
} catch (e) {
// TODO confirm that this causes perform to fail too if not handled
gen.throw(e);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment