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

asynchrony-di

v0.1.0-3

Published

An unopinionated asynchronous Dependency Injector and Orchestrator.

Downloads

7

Readme

Synopsis

An unopinionated asynchronous Dependency Injector and Orchestrator.

The need for another Dependency Injection Framework

Asynchrony DI was created at StackRoute (Github) to solve the problem of asynchronous dependency injection and orchestration of extensible counters in it's Quiz Framework, for awarding badges to quiz players in real-time. For instance, when the player wins his 10th quiz in a streak, we could award him a "Super Streak" badge. The challenges were as follows:

  1. Counters ("Winning Streak") and badges ("Super Streak"), are extensible. This means, new counters and badges could be added to the platform, and counters that have to be evaluated for any given event may increase.
  2. Counters need to be evaluated only once. A cached value needs to be returned when it is depended upon subsequently.
  3. To award the badges to the player in real-time, they need to be evaluated with the highest priority, which in turn require that their dependent counters be evaluated. This requires an IOC / DI framework.
  4. Counter values are stored in a shared In-Memory store, which can be retrieved with an async call.

As such, we first evaluated wagner-core, orchestrator, and Angular's di. Wagner and Angular's di are designed to bootstrap functions as dependencies, which are called during runtime in a synchronous fashion. This would not allow for returning and caching of asynchronous data. Wagner's synchronous approach would not let us retrieve counter values from an external data store. It's asynchronous dependencies, on the other hand, does not cache responses for re-use. Orchestrator is good at orchestrating and running dependencies in the right order, but lacks the ability to inject asynchronous cached values. Hence, we created Asynchrony-DI package, which would cache values retrieved in an asynchronous manner, and also orchestrate dependency execution.

Code Example

Installation

use npm to install the asynchrony-di module.

npm install asynchrony-di --save

Get a reference:

var Asynchrony = require('asynchrony-di');
var asynchrony = new Asynchrony();

Load it up with stuff to retrieve:

asynchrony.add('thing1',[function(done){
  setTimeout(function() {
    done(null, 'foo')
  });
}]);

asynchrony.add('thing2', [function(done){
  setTimeout(function() {
    done(null, 'bar');
  });
}]);

These dependencies are not evaluated until depended upon.

Run the tasks:

asynchrony.invoke(['thing1', 'thing2', function (t1, t2) {
  console.log(t1); // prints foo;
  console.log(t2); // prints bar;
}]);

API Reference

Add a task

asynchrony.add(name,[deps,fn]);

Parameter Type Description

name : String The name of the task.

deps : Task names to be executed before running the given task, it is optional.

fn : Function The actual function that gets executed when the given task is invoked.
Note: Take in a callback (done) for Async tasks

Example:

async_di.add('FirstName',[function(done){
    return done(null,'foo');
  }]);
async_di.add('SecondName',[function(done){
  return done(null,'bar')
}]);
async_di.add('FullName', ['FirstName','LastName', function(firstName, lastName, done) {
  //Form full name from the dependency values
    return done(null,firstName+" "+lastName);
}]);

Invoke

asynchrony.invoke(names[, fn(,value)]);

Execute a task

asynchrony.invoke(['thing1', function(t1){
  // do stuff
}]);
Parameter Type Description

names - String The names of the tasks to be invoked
fn - Function The callback function which will be executed after all the mentioned tasks are complete.
value - Object Possess the return values from the invoked tasks

Example

asynchrony.add('FullName', ['FirstName','LastName', function(firstName, lastName, done) {
  //Form full name from the dependency values
    return done(null,firstName+lastName);
}]);

asynchrony.invoke([‘FullName’, function(fullName){
  //Perform something after getting full name
  console.log(fullName);
}]);

Invoke Remaining Dependencies

asynchrony.invokeRemainingTask (fn);

Execute tasks which weren’t explicitly invoked

asynchrony.invokeRemainingTask (function(){
  // do something after all the remaining tasks are completed
});

Parameter Type Description

fn Function - The callback function which will be executed after all the remaining tasks are complete.

Example

asynchrony.add('FirstName',[function(done){
  // return done(null,firstName);
}]);
asynchrony.add('SecondName',[function(done){
  // return done(null,secondName)
}]);
asynchrony.invoke( [‘FirstName’, function(firstName) {
  //do something with firstname
}]);
asynchrony.invokeRemainingTask(function(){
  //do something after lastname is also executed
});

Tests

Asynchronous dependency injection test

var Asynchrony = require('asynchrony-di');
var should = require('should');
describe('Async Dependency Injection', function() {
  it('Basic Scenario for async test', function(done) {
    var asynchrony = new Asynchrony();

    var rand = (Math.random()*99387593793);
    var count = 0;

    asynchrony.add('thing1', [function(done) {
      setTimeout(function() {
        count++;
        return done(null, rand);
      },1000);
    }]);

    count.should.be.exactly(0);

    asynchrony.invoke(['thing1', function(thing1) {
      count.should.be.exactly(1);
      thing1.should.be.exactly(rand);
      done();
    }]);
  });
});

Multiple Dependencies Invocation

var Asynchrony = require('asynchrony-di');
var should = require('should');
describe('Async Dependency Injection', function() {
  it('Multiple Dependencies Invocation', function(done) {
    var asynchrony = new Asynchrony();

    var rand1 = (Math.random()*958728493827);
    var rand2 = (Math.random()*958728493827);
    var count1 = 0;
    var count2 = 0;

    asynchrony.add('thing1', [function(done) {
      setTimeout(function() {
        count1++;
        return done(null, rand1);
      }, 1000);
    }]);

    asynchrony.add('thing2', [function(done) {
      setTimeout(function() {
        count2++;
        return done(null, rand2);
      });
    }]);

    count1.should.be.exactly(0);
    count2.should.be.exactly(0);

    asynchrony.invoke(['thing1', 'thing2', function(t1, t2) {
      t1.should.be.exactly(rand1);
      t2.should.be.exactly(rand2);
      count1.should.be.exactly(1);
      count2.should.be.exactly(1);
      done();
    }]);
  });
});

Nested Dependency Invocation

var Asynchrony = require('asynchrony-di');
var should = require('should');
describe('Async Dependency Injection', function() {
  it('Nested Dependency Invocation', function(done) {
    var asynchrony = new Asynchrony();

    var rand1 = Math.random() * 1837953092;
    var rand2 = Math.random() * 5849382729;

    var count1 = 0;
    var count2 = 0;

    asynchrony.add('thing1', [function(done) {
      setTimeout(function() {
        count1++;
        return done(null, rand1);
      }, 300);
    }]);

    asynchrony.add('thing2', ['thing1', function(t1, done) {
      setTimeout(function() {
        count2++;
        return done(null, t1+rand2);
      },1000);
    }]);

    count1.should.be.exactly(0);
    count2.should.be.exactly(0);

    asynchrony.invoke(['thing2', function(t1) {
      t1.should.be.exactly(rand1 + rand2);
      count1.should.be.exactly(1);
      count2.should.be.exactly(1);
      done();
    }]);
  });
});

Extra Nested Multiple Dependencies

var Asynchrony = require('asynchrony-di');
var should = require('should');
describe('Async Dependency Injection', function() {
  it('Extra Nested Multiple Dependencies', function(done) {
    var asynchrony = new Asynchrony();

    var rand1 = Math.random() * 1837953092;
    var rand2 = Math.random() * 5849382729;
    var rand3 = Math.random() * 5838308403;

    var count1 = 0;
    var count2 = 0;
    var count3 = 0;

    asynchrony.add('thing1', [function(done) {
      setTimeout(function() {
        count1++;
        return done(null, rand1);
      }, 300);
    }]);

    asynchrony.add('thing2', ['thing1', function(t1, done) {
      setTimeout(function() {
        count2++;
        return done(null, t1+rand2);
      },400);
    }]);

    asynchrony.add('thing3', ['thing1', 'thing2', function(t1,t2, done) {
      setTimeout(function() {
        count3++;
        return done(null, t1+t2+rand3);
      }, 100);
    }]);

    count1.should.be.exactly(0);
    count2.should.be.exactly(0);
    count3.should.be.exactly(0);

    asynchrony.invoke(['thing3', 'thing2', 'thing1', function(t3,t2,t1) {
      t1.should.be.exactly(rand1);
      t2.should.be.exactly(rand1+rand2);
      t3.should.be.exactly(2*rand1+rand2+rand3);
      count1.should.be.exactly(1);
      count2.should.be.exactly(1);
      count3.should.be.exactly(1);
      done();
    }]);
  });
});

Remaining Task Execution

var Asynchrony = require('asynchrony-di');
var should = require('should');
describe('Async Dependency Injection', function() {
  it('Remaining Task Execution Test', function(done) {
    var asynchrony = new Asynchrony();

    var rand1 = (Math.random()*99387593793);
    var rand2 = (Math.random()*67674367647);
    var rand3 = (Math.random()*19928738278);
    var count1 = 0;
    var count2 = 0;
    var count3 = 0;

    asynchrony.add('thing1', [function(done) {
      setTimeout(function() {
        count1++;
        return done(null, rand1);
      },200);
    }]);
    asynchrony.add('thing2', [function(done) {
      setTimeout(function() {
        count2++;
        return done(null, rand2);
      },300);
    }]);
    asynchrony.add('thing3', [function(done) {
      setTimeout(function() {
        count3++;
        return done(null, rand3);
      },100);
    }]);
    count1.should.be.exactly(0);
    count2.should.be.exactly(0);
    count3.should.be.exactly(0);
    asynchrony.invoke(['thing1', function(thing1) {
      count1.should.be.exactly(1);
      count2.should.be.exactly(0);
      count3.should.be.exactly(0);
      thing1.should.be.exactly(rand1);
      asynchrony.invokeRemainingTask(function(err,data){
        //data is an object(key:value) which has Remaining dependency value. Key is the name of the dependency and value which will be equal to returned value of the invoked dependency.
        data['thing2'].should.be.exactly(rand2);
        data['thing3'].should.be.exactly(rand3);
        count1.should.be.exactly(1);
        count2.should.be.exactly(1);
        count3.should.be.exactly(1);
        done();
      });
    }]);
  });
});

License

MIT