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

stepthrough

v0.1.0

Published

Write super-clean async code with promises.

Downloads

5

Readme

Stepthrough Build Status Dependency Status

Write super-clean async code with promises.

Summary

Promises work great to reduce "right-ward drift" as seen with code using regular node-style callbacks. It also eases error handling, relieving you from the necessity to check for errors after each asynchronous step.

However, I found code that goes further than merely processing return values in a chain (comparable to chaining synchronous function calls) still too noisy, and writing too cumbersome.

With Stepthrough, you can use fulfilled promises in later steps without having to call then, and with access to more than one "return value" without explicitly specifying variables in an outer scope up-front.

When using CoffeeScript, the resulting code looks very close to regular synchronous code blocks.

Code example

In this example, we attempt to build some kind of email message piece by piece before sending it.

stepthrough = require "stepthrough"

sendMail = ->
  stepthrough [
    -> @name = "Meryn Stol" # real
    -> @email = "[email protected]" # real
    -> @subject = consoleAPI.askForLine "Message subject" # promise
    -> @body = consoleAPI.askForText "Message body" # promise
    -> @location = locationAPI.guessFriendlyName() # promise
    -> @blurp = "\n\nWritten in #{@location}" # real
    -> @body = @body + @blurp
    -> @signature = signatureAPI.signMessage @name, @email, @subject, @body
    -> @mailResult = mailAPI.send @name, @email, @subject, @body + @signature
    -> console.log "Successfully sent your message '#{@subject}' at #{@mailResult.getFriendlyTime()}."
  ]

How Stepthrough works

In short, stepthrough steps through an array of step functions. It returns a promise which is fulfilled when all steps are completed.

A step function can get and set properties on a provided memo object. This memo object essentially takes over the role of what normally be the local function scope in typical synchronous code.

After a step function has returned, Stepthrough will do the following:

  1. It inspects the current properties of the memo object. If some of these properties are promises, Stepthrough will wait until they are fullfilled.
  2. If the step function returns a promise, then Stepthrough will also wait until this promise is fulfilled before continuing with the next step.

What happens next depends on whether the promises are fulfilled:

  • If all promises (those set on the memo object, and the one returned, if any) are fulfilled, the memo object gets updated with the fulfiflled values and the next step function is called. If this step was the last step, then the promise returned by stepthrough is fulfilled.
  • If any of the promises are rejected, then the step is considered to have failed, and Stepthrough won't execute any of the following steps. The promise returned by stepthrough is then rejected, unless a special error handler is specified.

How it's better

  1. No need to define var's up-front in an outer function context. You can set any value you want.
  2. No need to think about whether the value you set is a real value or rather a promise for a value. Functions that return a promise appear in the code without any added noise, and are included without any extra effort.
  3. No need to assign any fulfilled value (normally passsed to of callback to then) to a variable in the outer function context. This will save you one line of code for any value of promise you need to have available further down in the chain.

Usage

stepthrough(steps)

You simply call stepthrough with an array containing any number of functions. These functions are called in turn with the value of memo as both the function context (this) and the first argument for the function.

Providing an initial value for the memo object

stepthrough(initialMemo, steps)

Optionally, you may provide a memo object as first argument. This object will be used as the initial value for the memo object. The properties of this object will be modified. The object reference stays the same. Calling stepthrough(steps) is the same as calling stepthrough({}, steps)

Providing an error handler

errorHandler = function(err, memo) { 
  console.log(this) // prints final value of the memo object
  console.log(memo) // idem
  throw err 
}
stepthrough(memo, steps, errorCallback)

Additionally, you may provide an error handler function as last argument. This error handler has access to the final version of the memo object. This is useful when you want to do any cleanup, for example closing file-descriptors or rolling back a transaction. Essentially, this function as the catch clause of a try...catch block.

If the error handler does not throw an error, the promise returned by stepthrough will be fulfilled anyway.

Credits

The initial structure of this module was generated by Jumpstart, using the Jumpstart Black Coffee template.

License

stepthrough is released under the MIT License.
Copyright (c) 2013 Meryn Stol