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

nbs

v3.1.1

Published

non-blocking synchronization(nbs:) in nodejs

Downloads

18

Readme

non-blocking synchronization(nbs:) in nodejs

RECOMENDED: use fibext instead. domain is optional for your own choice

I do not like Promise, yes I promise. This package is extended from fibers and domain, with much more friendly api(run/wait/resume), much more stronger error handling, much more tolerable for nested run, and aslo working in sync-callback.

Features

  • use run/wait/resume to archive fiber functionality, avoid callback hell
  • without explicit reference to call wait and resume
  • strong error handle and subsequent error handle for any scene, like thrown in sync/async callback, thrown before resume
  • tolerable nested run, no matter whether you call resume in n-th callback, run another fiber stack in async mode, or even wait another fiber stack paused!
  • using pair.resume and pair.wait for a synchronous callback is ok!
  • supply express middleware to wrap every request
  • use nbs.wrap to wrap the node core module's async function run as 'sync' style, like var data = fs.readFile(xxx)

Installation

npm install --save nbs

Simple usage

var nbs = require('../index'), wait = nbs.wait, resume = nbs.resume;
var fs = nbs.wrap(require('fs'));//wrap the node module

nbs.run(function(){
  var fileContent = fs.readFile('xxx');//it will return the file data directly

  nbs.sleep(1000);//sleep 1s

  //return value from the callback
  setTimeout(function(){
    resume(null, 'wake up');
  }, 1000);
  console.log(wait());//wake up
});

Used with express

app.use(nbs.express());//error will be redirected to error middleware
app.get('/sleep', function(req, resp){
  nbs.sleep(1000);
  resp.send('wake up').end();
});

with custom error handling:

app.use(nbs.express({
  //custom error handler
  onError: function(err, req, resp){
    resp.status(500).send(err.message).end();
  },
  //if supplied, then the subsequent error will be caught by this listener
  onSubError: function(err){
    console.log('caught subsequent error');
  }
}));
app.get('/sleep', function(req, resp){
  nbs.sleep(1000);
  resp.send('wake up').end();
});

Run with synchronous callback

function funcWithSyncCallback(cb){
  cb();
}

nbs.run(function(){
  console.log('start');

  var pair = nbs.pair();
  funcWithSyncCallback(function(){
    pair.resume();
  });
  pair.wait();//will not hung here!

  console.log('end');
});

Parallel the async

function get(url, cb){//get the response data from url
  //cb(err, data)
}

nbs.run(function(){
  get('url1', resume);
  get('url2', resume);
  get('url3', resume);

  //data1 may not be the url1's result! it can be url2/url3's result too. 
  //you should not rely on that. same to data2/data3
  var data1 = wait();
  var data2 = wait();
  var data3 = wait();

  console.log(data1, data2, data3);
});

More usages!

Please refer to the test cases to get more usage examples, like configuration, error handling, nested run, parallel run, etc.

API

nbs.config(options)

set the global configuration. options has:

  • onError: function(err). the error handler. defaut handler will emit process's uncaughtException event if there is listener at this event or it will crash the process(domain's behavior).
  • onSubError: function(err). the subsequenct error handler. default is null. if you supplied one, then the subsequent error from the nbs will be caught by it. subsequent errors are mainly caused by the async jobs.

nbs.resetConfig()

reset the global config.

nbs.run(func, [emitter1, emitter2, ...], [errorHandler], [subErrorHandler])

create a nbs-fiber stack, make the func to run in this stack, and any error thrown in this func and its async callbacks will be caught!

  • func: the target function that its subsequent call chain need to be run as-like 'sync'
  • emitterN: you can put the event emitters into this nbs to catch their error. see domain.bind
  • errorHandler: error handler only used by this nbs-fiber stack
  • subErrorHandler: subsequenct error handler only used by this nbs-fiber stack

nbs.wait([param1, param2, ...])

pause the nbs-fiber stack. wait should be used with resume and they must be in pairs. the params will be returned by the next-pair's resume method. wait will return the pair resume's params, and assume that the first param is error or null. if it's error, then throw it. if not, then return the remain parts of the resume params. if the resume params's length = 2, then return the second param to adapt node-style callback. see:

setTimeout(function(){
  resume(null, 'a');
});
wait();//return 'a'

setTimeout(function(){
  resume(null, 'a', 'b');
});
wait();//return ['a', 'b']

setTimeout(function(){
  resume(new Error('xxx'));
});
wait();//throw the error

//adapt to node-style callback
var fileContent = wait(fs.readFile('xxx', resume));

nbs.waitF(...)

same as nbs.wait(). the difference is waitF will return the pair resume's full params.

setTimeout(function(){
  resume('a');
});
waitF();//return 'a'

setTimeout(function(){
  resume('a', 'b');
});
waitF();//return ['a', 'b']

nbs.resume([param1, param2, ...])

resume the paused nbs-fiber stack. the params will be returned by this-pair's wait method; if the first param is an Error, then the pair wait method will throw the error, same to the first param is arguments object and the arguments's first param is an Error.

nbs.waitable()

check whether current stack is in the nbs-fiber stack

nbs.sleep(ms)

sleep the current stack with the specified miliseconds. same as wait(setTimeout(resume, ms)).

nbs.express([options])

express middleware. if you put it in express, then the domain-middleware is not needed anymore. options has:

  • onError: function(err, req, resp). default handler will redirect the error to the next error middleware of express
  • onSubError: function(err). there is no req and resp in the function. it's useful to record the subsequenct error.

nbs.wrap(functionOrObject, [deepTheFunction])

wrap node-style async functions to instead run in 'sync' style and return the value directly. this assumes that the last parameter of the function is async callback.

if a single function is passed then a wrapped function is created. if an object is passed then a new object is returned with all functions wrapped.

there is no way to get the underlying function's return. if you need, please use the unwrapped ones, such as child_process.execFile's return child.

and you should not call the sync-style function from the wrap, like readFileSync, they will block the fiber stack. use underscore.pick or _.omit to omit the sync-style functions.

var readFile = nbs.wrap(require('fs').readFile);
var fs = nbs.wrap(_.pick(require('fs'), 'readFile', 'writeFile'));
var request = nbs.wrap(require('request'), true);//wrap request and request.get ...

var fileContent = readFile('example.txt');
var fileContent = fs.readFile('example.txt');

Coverage

run command npm run test-cov .

=============================== Coverage summary ===============================
Statements   : 98.08% ( 204/208 )
Branches     : 93.46% ( 100/107 )
Functions    : 100% ( 35/35 )
Lines        : 98.92% ( 183/185 )
================================================================================

Benchmark with cps

run command npm run bench to compare the setTimeout(fn, 0) operation

cps: 64.55777921239509 op/s 15.49 ms/op
nbs: 64.76683937823834 op/s 15.44 ms/op

License :

Licensed under MIT

Copyright (c) 2015 kiliwalk