Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

parley

Package Overview
Dependencies
Maintainers
2
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

parley - npm Package Compare versions

Comparing version 1.0.1 to 1.0.2

lib/private/Deferred.js

12

lib/parley.js

@@ -9,2 +9,3 @@ /**

var bluebird = require('bluebird');
var Deferred = require('./private/Deferred');

@@ -92,2 +93,13 @@

//
// ==================================================================
// Note: to temporarily switch to the prototype/constructor strategy,
// comment out the inline dictionary definition below in favor of
// this line: (i.e. just uncomment it)
// ```
// var π = new Deferred(opts.codeName, opts.handleExec);
// ```
// For more info & benchmarks, see:
// https://github.com/mikermcneil/parley/commit/5996651c4b15c7850b5eb2e4dc038e8202414553#commitcomment-20256030
// ==================================================================
// Build deferred object.

@@ -94,0 +106,0 @@ var π = {

2

package.json
{
"name": "parley",
"version": "1.0.1",
"version": "1.0.2",
"description": "Practical, lightweight flow control for Node.js. Supports callbacks and promises.",

@@ -5,0 +5,0 @@ "main": "lib/parley.js",

@@ -13,3 +13,3 @@ parley

doStuff({ foo: 123 })
.set({ bar: 456 })
.foo({ bar: 456 })
.exec(function (err, result){

@@ -24,3 +24,3 @@

doStuff({ foo: 123 })
.set({ bar: 456 })
.baz({ bar: 456 })
.then(function (result){

@@ -27,0 +27,0 @@

@@ -48,3 +48,3 @@ /**

//
// Dec 20, 2016 (take 4): (after removing pretty-print)
// Dec 20, 2016 (take 4): (after removing pretty-print, BEFORE switching to the constructor approach)
// ================================================================================================================

@@ -55,3 +55,3 @@ // baseline.benchmark.js

// • b e n c h m a r k s •
// • (instantiation) °
// • °
// ------------------------------------

@@ -89,8 +89,75 @@ // parley(handler)

//
// • The additional time added by calling .exec() (vs. just building) is actually a NEGATIVE number
// in some cases. i.e. calling .exec() does not add any noticeable latency.
// • The additional time added by calling .exec() (vs. just building) is really only
// visible now, AFTER removing pretty-print. It's a difference of 100,000 ops/sec.
//
// • By itself, switching to a Deferred constructor doesn't really improve performance
// by THAT much. In some cases, it actually makes it worse (e.g. consistent decrease
// in ops/sec for the first 2 benchmarks: just_build, build_and_exec). BUT it does
// ever-so-slightly increase performance for both mock "find" mock "validate".
// The question is: "why?" My guess is that it has something to do w/ accessing
// `this` being slower than closure scope, and thus outweighing the gains of faster
// construction. But even then, that wouldn't explain "just_build" being slower, so
// it's probably not that...
//
// • Reducing the number of `this`/`self` references did not seem to make any sort of
// meaningful difference on performance. (see 1d8b6239de2cd84ac76ee015d099c3c5a7013989)
// *******UPDATE*******:
// Actually -- it might... after removing two unncesssary `this` assignments from the
// CONSTRUCTOR itself, performance for "just_build" shot up to where it was for the
// original closure approach (and possibly a bit higher). Still, this is negligible
// at the moment, but it's probably an effect that is more pronounced when overall ops/sec
// are orders of magnitude higher (e.g. in the millions instead of the hundreds of thousands.)
// Even then-- this is still less important than one might expect!
//
// • Aside: using a standalone function declaration (rather than invoking a self-calling function)
// increases performance, like you might expect. Whether it's enough to matter is probably
// situational. In the case of the commit where this observation was added to the code base,
// it made a difference of ~1,000,000 ops/sec for the "NAKED mock validate" benchmark, and a
// difference of ~20,000 ops/sec for the "validate w/ .exec()" benchmark. Worth it...?
// No. Inline function declarations are NEVER worth it. But in some cases it might be worthwhile
// to pull out shared futures used by self-invoking functions and drop them into a separate module.
// *******UPDATE*******:
// Just verified that, by moving the inline function to a separate file, performance for the
// "NAKED mock validate" went up by an ADDITIONAL 2,000,000 ops/sec, and by an ADDITIONAL
// ~20,000 ops/sec for the "validate w/ .exec()" benchmark. So, in conclusion, the answer to the
// question of "Worth it?" is a resounding YES -- but only for a hot code path like this. For
// other bits of code, the advantages of keeping the logic inline and avoiding a separate,
// weirdly-specific file, are well worth it. And as for INLINE named function declarations?
// They're still never worth it. Not only do they clutter the local scope and create scoffable
// confusion about flow control (plus all the resulting bug potential), they aren't even as fast
// as pulling out the code into a separate file. (Presumably this is because V8 has to make sure
// the inline function can access the closure scope.)
//
// • It is worth noting that, despite how exciting the previous notes about pulling out self-invoking
// functions was, when attempted with the mock "find" fixture, the relevant benchmarks showed no
// noticeable improvement (i.e. because they're doing something asynchronous.)
//
// • Swapping out non-standard variable names (e.g. π) did not have any noticeable effect.
//
// • When using the constructor+prototype approach, accessing `this` is slow. It's not THAT bad,
// but it is definitely a thing. Note that it is somewhat worse if in the constructor-- and
// also worse on assignment (this.foo = x) than on access (var x = this.foo).
//
// • When using the closure approach, adding new methods dynamically is slow. This doesn't seem
// to be because defining new functions is slow, per se. Rather it seems to have to do with
// mutating the object after it's already been created. As a middle ground, it seems that relying
// on Lodash's built-in optimizations is the way to go. Simply changing from `deferred.meta = ...`
// to `_.extend(deferred, { meta: ... })` split the difference as far as performance. It improved
// the performance of the 'mock validate with .exec()' benchmark by ~50k-60k ops/sec; i.e. ~20%)
//
// • STILL BE CAREFUL when using the closure approach. Even with the _.extend() trick, performance
// decreases as more and more methods are added, whether or not they're within the same `.extend()`
// call. BUT: What's still unclear is if this is due to function construction, or something else.
// In this case, in practice, tricks would need to be used to circumvent the need for closure scope
// access (i.e. prbly .bind()). But the answer to the question can actualy be figured out regardless--
// by defining stub functions once per process.
// *******UPDATE*******:
// Well, the answer is that the function construction must have mattered somewhat, but even after
// pulling the entire dictionary of methods out (and pretending they're static), the performance is
// still lower than when _.extend() is used to attach only ONE method-- even when that one method is
// defined inline. So, at the end of the day, we're just going to have to deal with the fact that,
// if we add methods to the Deferred dynamically and construction-time, it's going to be slower and
// slower for every additional method we add.
// ╔═╗╦ ╦╦╔╦╗╔═╗

@@ -103,3 +170,2 @@ // ╚═╗║ ║║ ║ ║╣

// •~ between 21,000 and 23,500 ops/sec (Dec 20, 2016)
function just_build(){

@@ -117,5 +183,2 @@ var deferred = parley(function(handlerCb) { return handlerCb(); });

// •~ between 21,000 and 23,000 ops/sec (Dec 20, 2016)
// --SAME AS ABOVE, basically -- like 200-500 ops/second slower, tops --
// (and keep in mind that's below the % error margin)
function build_AND_exec(){

@@ -122,0 +185,0 @@ var deferred = parley(function(handlerCb) { return handlerCb(); });

@@ -8,5 +8,5 @@ /**

var parley = require('../../');
var helpFind = require('./private/help-find.util');
/**

@@ -54,44 +54,11 @@ * find.fixture.js

// so we'll build and return a Deferred instead.
(function _determineFinalCb(proceed){
if (!_.isUndefined(explicitCb)) {
proceed(undefined, explicitCb);
}
else {
deferred = parley(function (deferredCb){
proceed(undefined, deferredCb);
});
}
// ~∞%°
})(function (unused, finalCb) {
if (unused) {
finalCb(new Error('Consistency violation: Unexpected internal error occurred before beginning with any business logic. Details: '+unused.stack));
return;
}//-•
if (!_.isUndefined(explicitCb)) {
helpFind(undefined, metadata, explicitCb);
}
else {
deferred = parley(function (deferredCb){
helpFind(undefined, metadata, deferredCb);
});
}//>-
// Now actually do stuff.
// In this case, we'll just pretend, since this part doesn't matter.
// (we just wait a few miliseconds, and then send back an array consisting
// of one item: the `criteria` that was received.)
setTimeout(function (){
var fakeResult = [ metadata.criteria ];
// Note that, as a way for our test cases to instrument the outcome,
// we check `metadata.criteria` here, and if it happens to be `false`
// or `null`, then we trigger an error instead.
if (metadata.criteria === false) {
return finalCb(flaverr('E_SOME_ERROR', new Error('Simulated failure (E_SOME_ERROR)')));
}
if (_.isNull(metadata.criteria)) {
return finalCb(new Error('Simulated failure (catchall / misc. error)'));
}
return finalCb(undefined, fakeResult);
}, 25);
});//</ self-invoking function>
// If we ended up building a Deferred above, we would have done so synchronously.

@@ -111,7 +78,9 @@ // In other words, if there's going to be a Deferred, we have it here.

// At this point, we might opt to attach some methods to our Deferred.
deferred.where = function (clause){
metadata.criteria = metadata.criteria || {};
metadata.criteria.where = clause;
return deferred;
};
_.extend(deferred, {
where: function(clause) {
metadata.criteria = metadata.criteria || {};
metadata.criteria.where = clause;
return deferred;
}
});

@@ -118,0 +87,0 @@ // When we're confident that our Deferred is ready for primetime,

@@ -8,5 +8,5 @@ /**

var parley = require('../../');
var helpValidate = require('./private/help-validate.util');
/**

@@ -45,28 +45,12 @@ * validate.fixture.js

// so we'll build and return a Deferred instead.
(function _determineFinalCb(proceed){
if (!_.isUndefined(explicitCb)) {
proceed(undefined, explicitCb);
}
else {
deferred = parley(function (deferredCb){
proceed(undefined, deferredCb);
});
}
// ~∞%°
})(function (unused, finalCb) {
if (unused) {
finalCb(new Error('Consistency violation: Unexpected internal error occurred before beginning with any business logic. Details: '+unused.stack));
return;
}//-•
if (!_.isUndefined(explicitCb)) {
helpValidate(undefined, explicitCb);
}
else {
deferred = parley(function (deferredCb){
helpValidate(undefined, deferredCb);
});
}//>-
// Now actually do stuff.
// ...except actually don't-- this is just pretend.
// All done.
return finalCb();
});//</ self-invoking function>
// If we ended up building a Deferred above, we would have done so synchronously.

@@ -86,6 +70,53 @@ // In other words, if there's going to be a Deferred, we have it here.

// At this point, we might opt to attach some methods to our Deferred.
deferred.meta = function (_meta){
metadata.meta = _meta;
return deferred;
};
// --(1)-------------------------------------------------------
// --too slow:
// --(e.g. 212k ops/sec)
// deferred.meta = function (_meta){
// metadata.meta = _meta;
// return deferred;
// };
// --(2)-------------------------------------------------------
// --perfectly fast, but doesn't do anything:
// --(e.g. 373k ops/sec)
// var theMeta = function (_meta){
// metadata.meta = _meta;
// return deferred;
// };
// --(3)-------------------------------------------------------
// --somewhat better than the original!!...
// --(e.g. 273k ops/sec)
// --....but problematic, because it doesn't actually mutate
// --the original deferred, which could cause inconsistencies.
// deferred = _.extend({
// meta: function (_meta){
// metadata.meta = _meta;
// return deferred;
// }
// }, deferred);
// --(4)-------------------------------------------------------
// --considerably better than the original!!
// --(Even more than #3... plus it's totally valid!)
// --(e.g. ~268k-292k ops/sec)
_.extend(deferred, {
meta: function (_meta){
metadata.meta = _meta;
return deferred;
},
// Uncomment these methods for testing performance:
// (this function gets slower and slower the more you add dynamically like this)
// ================================================================================================
// a: function (beep, boop) { console.log(Math.random()+'hi0'); return deferred; },
// b: function (baa, baaa, black, sheep) { console.log(Math.random()+'hi1'); return deferred; },
// c: function (beep, boop) { console.log(Math.random()+'hi2'); return deferred; },
// d: function (baa, baaa, black, sheep) { console.log(Math.random()+'hi3'); return deferred; },
// e: function (beep, boop) { console.log(Math.random()+'hi5'); return deferred; },
// f: function (baa, baaa, black, sheep) { console.log(Math.random()+'hi5'); return deferred; },
// g: function (beep, boop) { console.log(Math.random()+'hi6'); return deferred; },
// h: function (baa, baaa, black, sheep) { console.log(Math.random()+'hi7'); return deferred; },
// i: function (beep, boop) { console.log(Math.random()+'hi8'); return deferred; },
// j: function (baa, baaa, black, sheep) { console.log(Math.random()+'hi9'); return deferred; },
// k: function (beep, boop) { console.log(Math.random()+'hi10'); return deferred; },
// l: function (baa, baaa, black, sheep) { console.log(Math.random()+'hi11'); return deferred; },
// ================================================================================================
});

@@ -97,1 +128,2 @@ // When we're confident that our Deferred is ready for primetime,

};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc