npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@playframe/promisync

v1.0.3

Published

Promises that Sync as you prefer

Downloads

2

Readme

PlayFrame

PromiSync

0.7 kB Promises that Sync as you prefer

Installation

npm install --save @playframe/promisync

Description

PromiSync will create a Promise engine on top of any scheduling implementation. So you get to decide when your then, catch and finally handlers are going to execute and if try catch wrap is required. By buidling PromiSync on top of OverSync we get a Promise implemetation with frame rendering engine under the hood.

Should work well mixed with any other Promise implementation or await syntax. Please submit issues if any found

Usage

const oversync = require('@playframe/oversync')
const promisync = require('@playframe/promisync')
// let's add `decrypt` and `encrypt` stages to standard flow
const sync = oversync(performance.now, requestAnimationFrame,
  ['next', 'decrypt', 'catch', 'then', 'finally', 'encrypt', 'render'])

const CryptoPromiSync = promisync(sync)

CryptoPromiSync.Promise
  .resolve(secret)
  .decrypt(...)
  .then(...)
  .encrypt(...)
  .render(...)
  .frame(...)
  .catch(...)

Build your own Promise

In this section we will create something different

For example you just want lazy promises for better rendering performance by delaying heavy tasks. You could just do:

const later = (f)=> requestIdleCallback(f, {timeout: 500})
const Lazyness = promisync({
    then: later,
    catch: later,
    finally: later
  })
Lazyness.Promise
  .resolve(1)
  .then(...)
  .catch(...)
  .finally(...)

AWS.config.setPromisesDependency(Lazyness.Promise);

Or almost immediate, but framerate friendly Promise implementation:

const afterFrame = (f)=> requestAnimationFrame(=> setTimeout(f))
const Framer = promisync({
      then: afterFrame,
      catch: afterFrame,
      finally: afterFrame,
      render: requestAnimationFrame
  })
Framer.Promise
  .resolve(
    // fetch and JSON parse are happening lazy on idle
    Lazyness.then(()=> fetch(...))
      .then((body)=> body.json())
  )
  // Framer's `then` will wait for current frame to render first
  .then(updateState)
  // `render` is part of Framer's promise chain
  .render((state, ts)=> updateDom(state))
  // if anything goes wrong
  .catch(...)

Look how much control over execution flow we gained by just using promises

And now the most aggressive Promise implemetation but with exception recovery

const trySyncronously = (f)=> try{f()} catch(e){f.r(e)}
const PromiSync = promisync({
      then: trySyncronously,
      catch: trySyncronously,
      finally: trySyncronously
})
PromiSync.Promise.resolve(1)
  .then(...)
  .then(...)
  .then(...)
  .catch(...)
  .then(()=> console.log('chained')) // This logs first

console.log('syncronously') // This logs second

Annotated Source

Importing @playframe/proxy

proxy = require '@playframe/proxy'

Cheaply marking any value as rejected

REJECTED = Symbol 'REJECTED'
mark_rejected = (error)=>
  error = Object error # Object wrapper for primitives
  error[REJECTED] = true
  error

Defining a higher order function that takes a prototype sync for our future promise chain. sync needs only to implement the scheduling and try catch if needed. Methods catch and finally behave in Promise manner

module.exports = (sync)=>

Lets use a tiny proxy implementation for creating trapped objects with the same methods as sync

  methods = Object.keys sync
  make_proxy = proxy methods

chained is a higher order function that takes a schedule function and handler f to wrap f into chain resolver and pass it to schedule. It returns a proxy object methods of which will be executed after f is resolved

  chained = (schedule)=>(f)=>

Please note that closures are _prefixed

    _done = false
    _result = null
    _chain = ID

    resolve = (result)=>
      unless _done
        _done = true
        schedule _chain
        _result = result

    reject = (error)=> resolve mark_rejected error

    schedule wrap = (a...)=>
      unless _done
        result = f a...
        if result and result.then
          result.then resolve, reject
        else
          resolve result
        result

    wrap.r = reject

    make_proxy (method, f, recover)->
      if recover
        return @_h(method, f).catch recover

      fill = if method is 'finally'
        (x)=> f x; _result

      else if method is 'catch'
        (x)=>
          if _result[REJECTED]
            _result[REJECTED] = false
            f _result, x
          else
            _result
      else
        (x)=>
          if _result[REJECTED]
            _result
          else
            f _result, x

      # ✌️ combinator for nested chains
      chained((fill)=>
        if _done
          sync[method] fill
        else
          # chain of closures to call later
          # `do` does `_chain` closure
          # and returns the second `=>`
          _chain = do (_chain)=>=>
            _chain()
            sync[method] fill
            return
      ) fill

Now lets copy all methods from sync into returned chain object by wrapping them in chained. Also lets define Promise property of our chain object.

  chain = methods.reduce ((chain, m)=>
    chain[m] = chained sync[m]
    chain
  ),
    Promise: Promise = (f)=>
      _fill = ID
      
      p = chained((fill)=>
        _fill = fill
      ) ID
      
      # f(resolve, reject)
      f _fill, (x)=> _fill mark_rejected x
      p

  Promise.resolve = (x)=> chain.then => x
  Promise.reject = (x)=> chain.catch => mark_rejected x

  Promise.race = (list)=> Promise (resolve, reject)=>
    {length} = list
    while length--
      list[length].then resolve, reject
    return

  Promise.all = (list)=> Promise (resolve, reject)=>
    {length} = list
    i = 0
    arr = Array length
    while i < length
      list[i].then (do (i)=>(x)=> # i closure
        arr[i] = x
        resolve arr unless --length
      ), reject
      i++
    return

  chain


# Identity function
ID = (x)=> x