Last active
April 11, 2021 00:47
-
-
Save neborn/8460ae8ff0b47ccf978ad91da6df1592 to your computer and use it in GitHub Desktop.
Use Task Hook
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
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