Duktape has a support for simple coroutines. Execution is strictly nesting: coroutine A resumes or initiates coroutine B, coroutine B runs until it yields or finishes (either successfully or through an uncaught error), after which coroutine A continues execution with the yield result.
Coroutines are created with new Duktape.Thread()
, which gets as its
sole argument the initial function where the new coroutine begins execution on
its first resume. The resume argument becomes the initial function's first (and
only) argument value.
A coroutine is resumed using Duktape.Thread.resume()
which takes the
following arguments: the coroutine to resume, the resume value, and (optionally)
a flag indicating whether the resume value is an ordinary value or an error to
be injected into the target coroutine. Injecting an error means that the resume
value will be "thrown" at the site of the target coroutine's last yield operation.
In other words, instead of returning with an ordinary value, the yield will
seemingly throw an error.
A coroutine yields its current execution using Duktape.Thread.yield()
which takes as its arguments: the value to yield, and (optionally) a flag indicating
whether the yield value is an ordinary value or an error to be thrown in the
context of the resuming coroutine. In other words, an error value causes the
resume operation to seemingly throw an error instead of returning an ordinary
value.
If a coroutine exists successfully, i.e. the initial function finishes by returning a value, it is handled similarly to a yield with the return value. If a coroutine exists because of an uncaught error, it is handled similarly to a yield with the error: the resume operation will rethrow that error in the resuming coroutine's context. In either case the coroutine which has finished can no longer be resumed; attempt to do so will cause a TypeError.
There are currently strict limitations on when a yield is possible. In short, a coroutine can only yield if its entire active call stack consists of plain Ecmascript-to-Ecmascript calls. The following prevent a yield if they are present anywhere in the yielding coroutine's call stack:
eval()
callFunction.prototype.call()
or Function.prototype.apply()
See How to use coroutines for examples.