Lua-like pseudo-coroutine for JavaScript/TypeScript using generator. Demo
TOC
- Installation
- Examples
- Error handling
- Golang-like defer
- Functions
- Class Coroutine
- Class ComposedCoroutine
npm install --save luacoro
import * as luacoro from 'luacoro'
// or
const luacoro = require('luacoro')
Example code is also displayed in the demo.
Can handle errors just like normal functions.
it('handles error', () => {
let result = ''
function* second (): luacoro.Iterator<{}> {
throw new Error('an error')
}
function* first (): luacoro.Iterator<{}> {
try {
yield second()
} catch (e) {
result += 'caught '
}
yield second()
}
const c = luacoro.create(first())
try {
c.resume()
} catch (e) {
result += e.message
}
expect(result).toEqual('caught an error')
})
luacoro.defer
works like Golang's defer.
Useful to clean up scene scoped resources.
Defer functions must be normal functions.
Not yield
able within them.
See examples/browser/src/guide.ts for example.
function addClickEffect () {
coro.add(function* (): luacoro.Iterator<{}> {
const e = document.createElement('div')
e.classList.add('guide-click-effect')
document.getElementById('guide').appendChild(e)
luacoro.defer(() => {
e.remove()
})
e.style.left = `${lastCursorPos.x}px`
e.style.top = `${lastCursorPos.y}px`
for (let i = 1; i <= clickEffectFrames; i++) {
const s = easingOut(i / clickEffectFrames)
e.style.transform = `translate(-50%, -50%) scale(${s}, ${s})`
e.style.opacity = `${1 - s}`
yield
}
})
}
create<T> (start?: Coroutinizable<T>): Coroutine<T>
Create a new coroutine to iterate start
first.
start
normally must be an iterator generated by a generator
implemented to yield
(or return
) values of the following 3 types:
-
o
: An instance of arbitary class or plainobject
|string
|Array
resume()
returnso
.- If
o
has await
field,resume()
returnsnull
througho.wait - 1
frames after that. The iterator is not resumed while this, which means that this coroutine waitsn
frames including the current frame.
-
n
: Anumber
resume()
returnsnull
.- After that,
resume()
returnsnull
throughn - 1
frames. The iterator is not resumed while this, which means that this coroutine waitsn
frames including the current frame.
-
i
: AnIterator
of the same type asstart
- When
i
isreturn
ed, the current iterator is terminated andi
is immediately started to iterate as the replacement. - When
i
isyield
ed, the current iterator is paused and pushed onto the stack, andi
is immediately started to iterate. Afteri
is terminated, the caller iterator is popped from the stack and continued to be iterated. At this time, the return value ofi
can be got.
- When
concurrent<T> (coroutines: Coroutinizable<T>[]): ComposedCoroutine<T>
Create a new coroutine to iterate all coroutines
concurrently.
This coroutine will never die.
Additional coroutines can be added by add<T>()
.
Dead coroutines will be removed automatically.
all<T> (coroutines: Coroutinizable<T>[]): ComposedCoroutine<T>
Create a new coroutine to iterate all coroutines
concurrently until the all of them are dead.
Dead coroutines will not be removed to keep array indexes of the yield
ed value.
Adding coroutines by add<T>()
is discouraged.
race<T> (coroutines: Coroutinizable<T>[]): ComposedCoroutine<T>
Create a new coroutine to iterate all coroutines
concurrently until one of them is dead.
Array indexes of the yield
ed value will be keeped.
Adding coroutines by add<T>()
is discouraged.
forever<T> (generator: SimpleGenerator<T>): Coroutine<T>
Create a new coroutine that repeats generating iterator and iterating it forever.
defer (fn: () => void)
Register fn
to be invoked when exiting the caller iterator.
Works like Golang's defer.
resume(resumeValue?: T): T
Resume the current iterator and receive the yielded value at the next frame. This method will return nulls forever after the coroutine stops.
stop(): void
Stop this coroutine.
get isAlive(): boolean
Whether this coroutine is alive.
Coroutine that wraps multiple iterators and yields results in an array.
add (coroutine: Coroutinizable<T>)
Add a coroutine
to iterate together.