Skip to content

townewgokgok/luacoro-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

70 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

luacoro-js

Build Status npm Dependency Status MIT License

Lua-like pseudo-coroutine for JavaScript/TypeScript using generator. Demo

TOC

Installation

npm install --save luacoro
import * as luacoro from 'luacoro'
// or
const luacoro = require('luacoro')

Examples

See examples/browser/src/.

Example code is also displayed in the demo.

Error handling

Can handle errors just like normal functions.

See src/index.spec.ts

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')
})

Golang-like defer

luacoro.defer works like Golang's defer. Useful to clean up scene scoped resources.

Defer functions must be normal functions. Not yieldable 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
    }
  })
}

Functions

Function create

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 plain object | string | Array

    • resume() returns o.
    • If o has a wait field, resume() returns null through o.wait - 1 frames after that. The iterator is not resumed while this, which means that this coroutine waits n frames including the current frame.
  • n: A number

    • resume() returns null.
    • After that, resume() returns null through n - 1 frames. The iterator is not resumed while this, which means that this coroutine waits n frames including the current frame.
  • i: An Iterator of the same type as start

    • When i is returned, the current iterator is terminated and i is immediately started to iterate as the replacement.
    • When i is yielded, the current iterator is paused and pushed onto the stack, and i is immediately started to iterate. After i is terminated, the caller iterator is popped from the stack and continued to be iterated. At this time, the return value of i can be got.

Function concurrent

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.

Function all

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 yielded value. Adding coroutines by add<T>() is discouraged.

Function race

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 yielded value will be keeped. Adding coroutines by add<T>() is discouraged.

Function forever

forever<T> (generator: SimpleGenerator<T>): Coroutine<T>

Create a new coroutine that repeats generating iterator and iterating it forever.

Function defer

defer (fn: () => void)

Register fn to be invoked when exiting the caller iterator. Works like Golang's defer.

Class Coroutine

Method resume

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.

Method stop

stop(): void

Stop this coroutine.

Accessor isAlive

get isAlive(): boolean

Whether this coroutine is alive.

Class ComposedCoroutine

Coroutine that wraps multiple iterators and yields results in an array.

Method add

add (coroutine: Coroutinizable<T>)

Add a coroutine to iterate together.