Nuanced Pterodactyl Monk

    sig-js

    0.5.5 • Public • Published

    sig

    Build Status

    high-level reactive-style programming in javascript

    var s = sig()
     
    s.map(function (x) {
      return x + 1
    })
      .filter(function (x) {
        return !(% 2)
      })
      .each(sig.log)
      .done()
     
    s.put(1) // 2
      .put(2)
      .put(3) // 4

    docs

    overview

    sources and targets

    Signals can have at most one source and multiple targets, where values and errors flow from the source to its targets.

    value propagation

    Values propagate from a source signal to its target signals using .put(). .put() sends the given value to the value handler of each of its targets. .then() is used to create a new target signal with a given handler function. To further propagate the value, handler functions should use .put() to send the value from the relevant signal (provided as the this context) to its target signals. Once the the handler function has completed its processing, it should tell the signal that its ready to handle the next value or error using .next().

    var s = sig()
     
    var t1 = s.then(function (v) {
      this.put(+ 1).next()
    })
    var u1 = t1.each(sig.log)
    u1.done()
     
    var t2 = s.then(function (v) {
      this.put(* 2).next()
    })
    var u2 = t2.each(sig.log)
    u2.done()
     
    s.put(3)
    // -- s --
    // | 3   | 3
    // v     v
    // t1    t2
    // | 4   | 6
    // v     v
    // u1    u2

    If any new values or errors are received before .next() has been called, they will get buffered, then popped off once the signal is ready to process them.

    Since sychronous handlers are likely to always call .next() at the end, .each() is available as a thin wrapper around .then() that calls .next() itself once the given function has been called.

    error handling

    Errors propagate from a source signal to its target signals using .throw(), much in the same way values propagate with .put(). catch is used to create a new target signal with a given error handler. As is the case for value propagation, the error handler needs to call .next() to tell the signal to handle the next value or error.

    var s = sig()
     
    var t1 = s.catch(function (e) {
      this.throw(e).next()
    })
    var u1 = t1.catch(sig.log)
    u1.done()
     
    var t2 = s.catch(function (e) {
      this.throw(e).next()
    })
    var u2 = t2.catch(sig.log)
    u2.done()
     
    s.throw(new Error('o_O'))
    // ---- s ----
    // | o_O     | o_O
    // v         v
    // t1        t2
    // | o_O     | o_O
    // v         v
    // u1        u2

    Error handler functions can also propagate values, which is useful for cases where a signal can recover from an error.

    var s = sig()
     
    s.catch(function () {
      this.put(null).next()
    })
      .each(sig.log)
      .done()
     
    s.put(21) // 21
      .throw(new Error('o_O')) // null
      .put(23) // 23

    If an error has put the signal into a state it cannot recover from, .kill() can be used to end the signal, regardless of whether there are still values to be sent.

    var s = sig()
      .catch(function () {
        this.kill()
      })
      .done()

    Note that .throw() and .catch() should always be used as a way to propagate and handle errors occuring in a chain of signals, as opposed to javascript's native throw and try-catch error handling, since signal processing can occur asynchronously (depending on how sig is being used).

    ending chains

    Once a signal chain has been set up, and values and errors can not propagate any further, .done() should be used to declare the end of the signal chain. Once the end of the signal chain is declared, the signals in the chain are unpaused for the first time to allow values and errors to start propagating.

    sig([23])
      .each(sig.log) // (nothing has been logged yet)
      .done() // 23 (the chain has been started, `23` has been logged)

    If no function is given to .done(), it will rethrow unhandled errors using javascript's native throw, then kill the last signal in the chain with .kill().

    var s = sig()
     
    s.map(function (v) {
      return v + 1
    })
      .filter(function (x) {
        return !(% 2)
      })
      .each(sig.log)
      .done()
     
    s.put(1) // 2
      .put(2)
      .put(3) // 4
      .throw(':/') // Error: :/

    .done() accepts a node.js-style callback function. If an error reaches the end of the signal chain, the callback function is called with the error as its first argument, then the last signal in the chain is killed using .kill().

    var s = sig()
     
    s.map(function (v) {
      return v + 1
    })
      .filter(function (x) {
        return !(% 2)
      })
      .each(sig.log)
      .done(function (e) {
        sig.log(|| 'done!')
      })
     
    s.put(1) // 2
      .put(2)
      .put(3) // 4
      .throw(':/') // :/
      .put(4)
      .put(5)

    If a signal in the chain has ended, the callback function is invoked without any arguments.

    var s = sig()
     
    s.map(function (v) {
      return v + 1
    })
      .filter(function (x) {
        return !(% 2)
      })
      .each(sig.log)
      .done(function (e) {
        sig.log(|| 'done!')
      })
     
    s.put(1) // 2
      .put(2)
      .put(3) // 4
      .end() // done!

    If any values propogate to the end of the signal chain, .done() will discard them.

    // nothing will get logged, `.done()` has discarded the values
    sig([1, 2, 3]).done().each(sig.log)

    disposal

    When a signal is no longer needed, .end() should be used. Ending a signal causes the signal to end each of its targets (and in turn, each target will end their own targets) and disconnects the signal from its source. Once the signal no longer has buffered values that it needs to send, its teardowns are called, its state is cleared and it is marked as ended. Signals marked as ended treat .put(), .throw() and .then() as no-ops. The immediate disconnecting of a signal is necessary to avoid memory leaks caused by signals with buffers that never clear.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.teardown(sig.log, 'ended').pause().put(23).end()
     
    s.resume()
    // 23
    // ended

    If the signal needs to be ended immediately, regardless of whether it still has values it needs to send, kill should be used.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.teardown(sig.log, 'ended').pause().put(23).kill() // ended

    Note that creating signals without ending them when their work is done will lead to memory leaks for the same reasons not removing event listeners will when using an event listener pattern.

    disconnects

    When a signal is ended, the chain of signals ending with it (if any) will no longer be sending values to it, so it can be removed from the chain. However, other signals in the chain cannot be ended, as sibling targets (targets with the same source) might still be around listening for new values. To prevent chains of unused target signals being kept in memory as a result of this, source signals forget a target signal when the target no longer has its own targets, putting the target in a 'disconnected' state. Targets keep a reference to their source, so a signal chain will be reconnected if a new target gets added at the end of the chain.

    var a = sig()
    var b = sig()
    var c = sig()
    var d = sig()
    var e = sig()
     
    a.then(b)
    b.then(c).done()
    b.then(d).done()
    //       a
    //       |
    //       v
    //  ---- b
    // |     |
    // v     v
    // c     d     e
     
    c.end()
    //       a
    //       |
    //       v
    //       b
    //       |
    //       v
    // c     d     e
     
    d.end()
    //       a
    //
    //
    //       b
    //
    //
    // c     d     e
     
    b.then(e).done()
    //       a
    //       |
    //       v
    //       b ----
    //             |
    //             v
    // c     d     e

    pausing and resuming

    When a signal is paused using pause, any values given to it by put are buffered. When the signal is resumed using resume, any buffered values are sent to the signal's targets, and any new values will be sent straight to the signal's targets (and not get buffered).

    var s = sig()
     
    s.each(sig.log).done()
     
    s.pause().put(21).put(23)
     
    s.resume()
    // 21
    // 23

    Note that signals start off paused and are unpaused for the first time either once the end of the signal chain is declared or once .resume() is called explicitly.

    redirection

    Sometimes, a function will return a single signal, though it has created one or more signal chains to send values to the returned signal.

    Redirecting using .put() from a different signal's value handling function will cause the signal to continue running indefinitely instead of disconnecting with its targets:

    function join(a, b) {
      var out = sig()
      var badRedirA = a.each(badRedir)
      var badRedirB = b.each(badRedir)
     
      function badRedir(v) {
        out.put(v)
        this.next()
      }
     
      return out
    }
     
    var a = sig()
    var b = sig()
    var out = join(a, b)
    var logOut = out.each(sig.log)
    logOut.done()
     
    // single line for targets, double line for redirections
    //
    //   a                      b
    //   |                      |
    //   v                      v
    // badRedirA ==> out <== badRedirB
    //                |
    //                v
    //             logOut
     
    a.put(21) // 21
    b.put(23) // 23
     
    out.end()
     
    // redirA and redirB are still connected :/
    //
    //   a                  b
    //   |                  |
    //   v                  v
    // redirA ==> out <== redirB
    //
    //
    //          logOut

    To redirect without this unwanted behaviour, .to() should be used to redirect values and errors to the returned signal, and to set these chains to disconnect when the returned signal is disconnected.

    If a function creates a signal chain, but the chain isn't returned, redirected or ended, this will lead to memory leaks. Rule of thumb: If you have a signal that outputs values, either return the signal, or redirect it to another returned signal.

    function join(a, b) {
      var out = sig()
      var redirA = a.to(out)
      var redirB = b.to(out)
      return out
    }
     
    var a = sig()
    var b = sig()
    var out = join(a, b)
    var logOut = out.each(sig.log)
    logOut.done()
     
    // single line for targets, double line for redirections
    //
    //   a                  b
    //   |                  |
    //   v                  v
    // redirA ==> out <== redirB
    //             |
    //             v
    //          logOut
     
    a.put(21) // 21
    b.put(23) // 23
     
    out.end()
     
    // redirA and redirB are disconnected!
    //
    //   a                  b
    //
    //
    // redirA     out     redirB
    //
    //
    //          logOut

    Note that .to() calls .done(). This means calling .to() declares the end of a signal chain and starts the signal chain, and .done() does not need to be called on redirected chains.

    sticky signals

    Sometimes, a signal needs to hold onto the last value it has sent out. When new targets arrive, they need to receive this last value instead of having them 'miss the bus' and only receive new values sent from the source signal. Sticky signals allow this.

    Sticky signals can be created using val.

    var v = sig.val(23)
    v.each(sig.log) // 23
    v.each(sig.log) // 23

    api

    sig([values])

    Creates a new signal. If a values array is given, it is used as the initial values sent from the signal.

    var s = sig([1, 2, 3])

    functions and methods

    The following sig methods are also accessible as static functions taking a signal as the first argument:

    put, then, done, next, end, kill, resolve, putTo, putEach, throw, catch, teardown, pause, resume, map, each, tap, filter, flatten, limit, once, then, to, redir, update, append, call, event

    For example, using the static counterpart of .put would look something like:

    var s = sig()
     
    s.each(sig.log).done()
     
    sig.put(s, 21) // 21
    sig.put(s, 23) // 23

    event catalogue

    disconnect

    Emitted when a connected signal disconnects.

    reconnect

    Emitted when a disconnected signal reconnects.

    flush

    Emitted after a signal has propagated any buffered values or errors, if any, after being resumed.

    end

    Emitted once a signal is about to end, before the signal clears its state and gets marked as ended. See disposal.

    ending

    Emitted once a signal has been scheduled to end via .end() or .kill(). See disposal.

    .put([v])

    Puts the value v through the signal, where v can be a value of any type.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.put(21) // 21
      .put(21) // 23

    .next()

    Tells the calling signal that it is done processing its most recent value or error, if any, and is ready to processing the next value or error.

    var s = sig()
    var t = s.then(sig.log)
    t.done()
     
    s.put(1) // 1
      .put(2)
     
    t.next() // 2

    .throw(e)

    Propogates the error instance e from the signal.

    var s = sig()
     
    s.catch(sig.log).done()
     
    s.throw(new Error('o_O')) // o_O

    .end()

    Ends the given signal, causing it to end its target signals and disconnect from its source, then clear its state once the signal no longer has values to send. See disposal.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.put(21) // 21
      .end()
      .put(23)

    .kill()

    Ends the given signal immediately, regardless of whether the signal still has values it needs to send. See disposal.

    sig().teardown(sig.log, 'Ended').end().kill() // Ended

    .then(fn[, args...])

    Creates and returns a new target signal with fn as its value handler. fn is called with each received value as its first argument and the created signal as its this context. The target signal is returned to allow for further signal chaining.

    var s = sig()
     
    s.then(function (v) {
      this.put(+ 2).next()
    })
      .each(sig.log)
      .done()
     
    s.put(21) // 23

    If extra arguments are provided, they are used as extra arguments to each call to fn.

    var s = sig()
     
    s.then(
      function (a, b, c) {
        this.put(+ b + c).next()
      },
      1,
      2
    )
      .each(sig.log)
      .done()
     
    s.put(20) // 23

    .then(t)

    Sets the calling signal as the source of the signal t and returns t.

    var s = sig()
    var t = s.then(sig())
     
    t.each(sig.log).done()
     
    s.put(23) // 23

    .done([fn])

    Ends a chain of signals (see ending chains). If an unhandled error reaches the end of the signal chain fn will be called with the error as its first argument and the last signal in the chain will be killed. If the signal ends without any errors fn will be called with no arguments. If fn isn't given, the first unhandled error will be rethrown using javascript's native throw.

    var s = sig()
     
    s.map(function (v) {
      return v + 1
    })
      .filter(function (x) {
        return !(% 2)
      })
      .each(sig.log)
      .done(function (e) {
        sig.log(|| 'done!')
      })
     
    s.put(1) // 2
      .put(2)
      .put(3) // 4
      .throw(':/') // :/
      .put(4)
      .put(5)

    .resume()

    Resumes the signal, causing the buffered values to propagate to the signal's targets and causing any new values to be sent to the signal's targets.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.put(21) // 21
      .pause()
      .put(23)
      .resume() // 23

    .catch(fn[, args...])

    Creates and returns a new target signal with fn set as its error handler. fn is called with each thrown error as its first argument and the created signal as its this context. The created signal is returned to allow for further signal chaining.

    var s = sig()
     
    s.catch(function (e) {
      sig.log(e)
      this.next()
    }).done()
     
    s.throw(new Error('o_O')) // o_O

    If extra arguments are provided, they are used as extra arguments to each call to fn.

    var s = sig()
     
    s.catch(function (a, b, c) {
      sig.log(a, b, c)
      this.next()
    }).done()
     
    s.throw(new Error('o_O'), '-_-', ':/') // o_O -_- :/

    .each(fn[, args...])

    Creates and returns a new target signal with a value handler that calls fn, then calls .next() immediately afterwards. This is useful for synchronous signals, where the value handler will almost always end with .next(). The target signal is returned to allow for further signal chaining. fn is called with each received value as its first argument and the created signal as its this context.

    var s = sig()
     
    s.each(function (v) {
      this.put(+ 2)
    })
      .each(sig.log)
      .done()
     
    s.put(21) // 23

    Note that if the handler is doing asynchronous work, it would make more sense to use .then, then call .next() when the asynchronous work completes.

    If extra arguments are provided, they are used as extra arguments to each call to fn.

    var s = sig()
     
    s.each(
      function (a, b, c) {
        this.put(+ b + c)
      },
      1,
      2
    )
      .each(sig.log)
      .done()
     
    s.put(20) // 23

    Since .each() is intended for use with synchronous functions, if fn throws an error using javascript's native throw, the error will be caught and as an error in the signal chain.

    .tap(fn[, args...])

    Creates and returns a new target signal with a value handler that calls fn, then propogates the received value unchanged, allowing a function to 'tap' into a signal chain.

    var s = sig()
     
    s.map(function (v) {
      return v + 1
    })
      .tap(sig.log)
      .filter(function (v) {
        return !(% 2)
      })
      .done()
     
    s.put(21) // 22
      .put(22) // 23
      .put(23) // 24

    .map(fn[, args...])

    Creates and returns a new target signal with a value handler that calls fn and outputs its return value. fn is called with each received value as its first argument and the created signal as its this context.

    var s = sig()
     
    s.map(function (v) {
      return v + 2
    })
      .each(sig.log)
      .done()
     
    s.put(21) // 23

    If extra arguments are provided, they are used as extra arguments to each call to fn.

    var s = sig()
     
    s.map(
      function (a, b, c) {
        this.put(+ b + c)
      },
      1,
      2
    )
      .each(sig.log)
      .done()
     
    s.put(20) // 23

    .map(v)

    Creates and returns a new signal with a value handler that simply outputs v for every value received by the signal. The created signal uses s as its source signal. fn is called with each received value as its first argument and the created signal as its this context.

    var s = sig()
     
    s.map(function (v) {
      return v + 2
    })
      .each(sig.log)
      .done()
     
    s.put(21) // 23

    If extra arguments are provided, they are used as extra arguments to each call to fn.

    var s = sig()
     
    s.map(
      function (a, b, c) {
        this.put(+ b + c)
      },
      1,
      2
    )
      .each(sig.log)
      .done()
     
    s.put(20) // 23

    .filter([fn[, args...]])

    Creates and returns a new taret signal with a value handler that calls fn to determine whether to output a recieved value. fn is called with each received value as its first argument and the created signal as its this context.

    var s = sig()
     
    s.filter(function (v) {
      return v % 2
    })
      .each(sig.log)
      .done()
     
    s.put(22).put(23) // 23

    If extra arguments are provided, they are used as extra arguments to each call to fn.

    var s = sig()
     
    s.filter(
      function (a, b, c) {
        return (+ b + c) % 2
      },
      1,
      2
    )
      .each(sig.log)
      .done()
     
    s.put(22) // 22
      .put(23)

    If fn isn't provided, an identity function is used, filtering values based on their truthyness.

    var s = sig()
     
    s.filter().each(sig.log).done()
     
    s.put(0).put(1) // 1

    .to(t)

    Redirects values and errors sent from the calling signal to signal t. The returned signal is a new signal that controls this redirection. When either it, s or t are ended, the redirection ends. to behaves differently to then, as it does not set the calling signal as the source of t.

    function join(a, b) {
      var out = sig()
      a.to(out)
      b.to(out)
      return out
    }
     
    var a = sig()
    var b = sig()
     
    join(a, b).each(sig.log).done()
     
    a.put(21) // 21
    b.put(23) // 23

    .redir(t)

    Alias for .to().

    function join(a, b) {
      var out = sig()
      a.redir(out)
      b.redir(out)
      return out
    }
     
    var a = sig()
    var b = sig()
     
    join(a, b).each(sig.log).done()
     
    a.put(21) // 21
    b.put(23) // 23

    .tap(t)

    Redirects values propagated by the calling signal to another signal t and returns a new signal that propagates the source signal's values unchanged. This allows a signal to 'tap' into another signal chain. Note that unlike .to(), .tap() does not implicately declare the end of a signal chain with .done().

    var s = sig()
    var t = sig()
     
    t.each(sig.log).done()
     
    s.map(function (v) {
      return v + 1
    })
      .tap(t)
      .filter(function (v) {
        return !(% 2)
      })
      .done()
     
    s.put(21) // 22
      .put(22) // 23
      .put(23) // 24

    Redirection will stop when t disconnects, when the returned signal disconnects or when the source signal disconnects. When t disconnects, the returned signal will continue to propagate the source signal's values.

    .flatten()

    Creates and returns a new target signal that outputs each non-array value in a series of possibly nested arrays.

    var s = sig()
     
    s.flatten().each(sig.log).done()
     
    s.putEach([1, [2, [3, [4, 5, [6, 7, 8, [9, [10]]]]]]])
    // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    .limit(n)

    Creates and returns a new target signal that only propogates the first n values it receives.

    var s = sig()
     
    s.limit(3).each(sig.log).done()
     
    s.put(21) // 21
      .put(22) // 22
      .put(23) // 23
      .put(24)
      .put(25)

    .once()

    Special case of limit where n === 1.

    var s = sig()
     
    s.once().each(sig.log).done()
     
    s.put(21) // 21
      .put(22)
      .put(23)

    .update(fn[, args...])

    Returns a new target signal that 'updates' to proxy the signal most recently generated by a function fn mapping the calling signal's output values.

    var s = sig()
     
    var lookup = {
      t: sig()
      u: sig()
    }
     
    s.update(function(k) { return lookup[k] })
     .each(sig.log)
     .done()
     
    s.put('t')
     
    lookup.t
     .put(1)  // 1
     .put(2)  // 2
     .put(3)  // 3
     
    s.put('u')
     
    lookup.u
     .put(4)  // 4
     .put(5)  // 5
     .put(6)  // 6
     
    lookup.t
     .put(7)
     .put(8)
     .put(9)

    If fn returns a non-signal, its result is ignored.

    If fn isn't given, an identity function is used as the default. This can be useful for turning a signal of signals into a single signal.

    var s = sig()
    var t = sig()
    var u = sig()
     
    s.update().each(sig.log).done()
     
    s.put(t)
     
    t.put(1) // 1
      .put(2) // 2
      .put(3) // 3
     
    s.put(u)
     
    u.put(4) // 4
      .put(5) // 5
      .put(6) // 6
     
    t.put(7).put(8).put(9)

    .append(fn[, args...])

    Returns a new target signal that proxies every signal generated by a function fn mapping the calling signal's output values. Each time a new signal is generated, it is 'appended' to the signals being tracked, so outputs of previous signals will still be proxied when a new signal is generated by fn.

    var s = sig()
     
    var lookup = {
      t: sig()
      u: sig()
    }
     
    s.append(function(k) { return lookup[k] })
     .each(sig.log)
     .done()
     
    s.put('t')
     
    lookup.t
     .put(1)  // 1
     .put(2)  // 2
     .put(3)  // 3
     
    s.put('u')
     
    lookup.u
     .put(4)  // 4
     .put(5)  // 5
     .put(6)  // 6
     
    lookup.t
     .put(7)  // 7
     .put(8)  // 8
     .put(9)  // 9

    If fn returns a non-signal, its result is ignored.

    If fn isn't given, an identity function is used as the default. This can be useful for turning a signal of signals into a single signal.

    var s = sig()
    var t = sig()
    var u = sig()
     
    s.append().each(sig.log).done()
     
    s.put(t)
     
    t.put(1) // 1
      .put(2) // 2
      .put(3) // 3
     
    s.put(u)
     
    u.put(4) // 4
      .put(5) // 5
      .put(6) // 6
     
    t.put(7) // 7
      .put(8) // 8
      .put(9) // 9

    .call(fn[, args...])

    Calls a function fn with the calling signal as its first argument and args as the remaining arguments. Useful for hooking custom functions into a signal chain.

    var s = sig()
     
    s.call(mul, 2).each(sig.log).done()
     
    s.putEach([1, 2, 3])
    // [2, 4, 6]
     
    function mul(s, n) {
      return s.map(function (v) {
        return v * n
      })
    }

    .event(name)

    Returns a new signal that propagates each event with the given name emitted by the signal. See the event catalogue for the events emitted by the signal.

    var s = sig()
     
    s.event('flush')
      .each(function () {
        sig.log('flush!')
      })
      .done()
     
    s.pause()
      .resume() // flush!
      .pause()
      .resume() // flush!

    .teardown(fn[, args...])

    Schedules fn to be called when the calling signal has ended. fn is called with the calling signal as its this context. Any state used by the signal should be deconstructed inside a teardown function. If the calling signal has already ended, fn is called immediately. See disposal.

    function tick() {
      var s = sig()
      var id = setInterval(resolve, 200, s)
     
      s.teardown(function () {
        clearInterval(id)
      })
     
      return s
    }
     
    var s = tick()
     
    s.each(sig.log).done()
     
    // this will cause the teardown function to get called
    s.end()

    .resolve([v])

    Sends the value v (or undefined if no value is given) from the calling signal, then ends the signal.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.resolve(21) // 21
      .put(23)

    .putEach()

    Sends each value in a values array from the calling signal.

    var s = sig()
     
    s.each(sig.log).done()
     
    s.putEach([1, 2, 3])
    // 1
    // 2
    // 3

    .putTo(t)

    Sends the signal as a value to signal t.

    var s = sig()
     
    s.update().each(sig.log).done()
     
    var t = sig()
    t.putTo(s).put(23) // 23

    sig.val([v])

    Creates and returns a new sticky signal. If v is given, it is used as the initial value for the created signal.

    var v = sig.val(23)
    v.each(sig.log).done() // 23
    v.each(sig.log).done() // 23

    sig.ensureVal(v)

    If a v is given, a sticky signal is returned with v as its initial value. If v is a signal, a new sticky signal is returned with v as its source.

    var v = sig.ensureVal(23)
    v.each(sig.log).done() // 23
     
    var s = sig()
    var t = sig.ensureVal(s)
     
    s.put(23)
    t.each(sig.log).done() // 23
    t.each(sig.log).done() // 23

    sig.any(values)

    Accepts an array of values, where each value can be either a signal or non-signal, and returns a signal that outputs an array containing the value and its corresponding signal's index in the array whenever one of the signals in the array changes.

    var s = sig()
    var t = sig()
     
    sig.any([s, 23, t]).each(sig.spread, sig.log).done()
     
    s.put(1) // 1 0
    t.put(3) // 3 2
    s.put(2) // 2 0
    t.put(1) // 1 2
    s.put(3) // 3 0

    sig.any(obj)

    Identical to sig.any(values), except it handles an object of key-value pairs instead of an array, where each value can be either a signal or non-signal. The values outputted from the signal are arrays, each containing the given value and its corresponding signal's key in the object.

    var s = sig()
    var t = sig()
     
    sig
      .any({
        a: s,
        b: 23,
        c: t
      })
      .each(sig.spread, sig.log)
      .done()
     
    s.put(1) // 1 a
    t.put(3) // 3 c
    s.put(2) // 2 a
    t.put(1) // 1 c
    s.put(3) // 3 a

    sig.all(values)

    Accepts an array of values, where each value can be either a signal or non-signal, and returns a signal that outputs an array of the current values of each signal and non-signal each time one of the values changes. Note that the returned signal will only start outputting once each signal in the array has put through its first value.

    var s = sig()
    var t = sig()
     
    sig.all([s, 23, t]).each(sig.log).done()
     
    s.put(1)
    t.put(3) // [1, 23, 3]
    s.put(2) // [2, 23, 3]
    t.put(1) // [2, 23, 1]
    s.put(3) // [3, 23, 1]

    sig.all(obj)

    Identical to sig.all(values), catch it handles an object of key-value pairs instead of an array, where each value can be either a signal or non-signal.

    var s = sig()
    var t = sig()
     
    sig
      .all({
        a: s,
        b: 23,
        c: t
      })
      .each(sig.log)
      .done()
     
    s.put(1)
     
    t.put(3)
    // {
    //   a: 1,
    //   b: 23,
    //   c: 3
    // }
     
    s.put(2)
    // {
    //   a: 2,
    //   b: 23,
    //   c: 3
    // }
     
    t.put(1)
    // {
    //   a: 2,
    //   b: 23,
    //   c: 1
    // }
     
    s.put(3)
    // {
    //   a: 3,
    //   b: 23,
    //   c: 1
    // }

    sig.merge(values)

    Accepts an array of values, where each value can be either a signal or non-signal, and returns a signal that outputs the values put through each signal in the array.

    var s = sig()
    var t = sig()
     
    sig.merge([s, 23, t]).each(sig.log).done()
     
    s.put(1) // 1
    t.put(3) // 3
    s.put(2) // 2
    t.put(1) // 1
    s.put(3) // 3

    sig.merge(obj)

    Identical to sig.merge(values), except it handles an object of key-value pairs instead of an array, where each value can be either a signal or non-signal. The values outputted from the signal are the values sent from each signal in the object.

    var s = sig()
    var t = sig()
     
    sig
      .merge({
        a: s,
        b: 23,
        c: t
      })
      .each(sig.log)
      .done()
     
    s.put(1) // 1
    t.put(3) // 3
    s.put(2) // 2
    t.put(1) // 1
    s.put(3) // 3

    sig.isSig(v)

    Returns true if v is a signal, false if it is not.

    sig.isSig(23) // => false
    sig.isSig(sig()) // => true

    sig.log(v)

    Logs the given arguments. Similar to console.log, except it does not rely on console as its this context and returns its first argument.

    var s = sig()
     
    s.filter()
      .map(sig.log)
      .map(function (v) {
        return v * 2
      })
      .each(sig.log)
      .done()
     
    s.putEach([0, 1, 1, 0])
    // 1
    // 1
    // 2
    // 2

    sig.putTo(v, s)

    The static form of .putTo(), except v can be a value of any time (it does not have to be a signal).

    install

    You can use this library as the npm package sig-js:

    npm i sig-js
    # or
    yarn add sig-js
    

    It can be used in both es-module-aware and commonjs bundlers/environments.

    // es module
    import sig from 'sig-js'
     
    // commonjs
    const sig = require('sig-js')

    It can also be used a <script>:

    <script crossorigin src="https://unpkg.com/sig-js/dist/umd/sig.js"></script>
     
    <script>
      sig()
    </script> 

    Install

    npm i sig-js

    DownloadsWeekly Downloads

    4

    Version

    0.5.5

    License

    MIT

    Unpacked Size

    72.4 kB

    Total Files

    14

    Last publish

    Collaborators

    • justinvdm