connect-debounce
Advanced tools
Comparing version 0.1.0 to 0.2.0
78
index.js
@@ -0,1 +1,3 @@ | ||
var createHash = require('crypto').createHash; | ||
/** | ||
@@ -15,45 +17,71 @@ * Debounce a function execution similar to underscore, but in | ||
function debounce(fn, wait, immediate) { | ||
var req = this, | ||
now = Date.now(), | ||
name, | ||
map = req.session._debounce; | ||
map, id; | ||
if (!fn || !fn.name) { | ||
throw new Error('Named function required.'); | ||
if (!fn) { | ||
throw new Error('Function required.'); | ||
} | ||
name = fn.name; | ||
if (!map) { | ||
map = req.session._debounce = {}; | ||
if (wait === true) { | ||
wait = null; | ||
immediate = true; | ||
} | ||
map = req.session._debounce || (req.session._debounce = {}); | ||
id = fn._hash || (fn._hash = createHash('md5').update(fn.toString()).digest('hex')); | ||
wait || (wait = opts.wait); | ||
map[id] || (map[id] = immediate ? 0 : Date.now()); | ||
if (!map[name] || map[name] + wait > now) { | ||
if (!immediate) { | ||
map[name] = now; | ||
// Try to run it later, need to wait. | ||
if (map[id] + wait > Date.now()) { | ||
setTimeout(function() { | ||
req.session.reload(function(err) { | ||
if (err) return fn(err); | ||
// We need to save the session because request is already closed | ||
// and session middleware will not do this for us. | ||
req.session.save(function(err) { | ||
if (err) fn(err); | ||
map = req.session._debounce; | ||
if (map[id] + wait < Date.now()) { | ||
debounce.call(req, fn, wait, true); | ||
} | ||
}); | ||
} | ||
}, wait + 10); | ||
return setTimeout(function() { | ||
// Run it immediately. | ||
} else { | ||
fn(); | ||
// Cleanup it delayed for the case it will be called again. | ||
setTimeout(function() { | ||
req.session.reload(function(err) { | ||
if (err) return fn(err); | ||
debounce.call(req, fn, wait, true); | ||
map = req.session._debounce; | ||
// Already cleaned up or a new timeout was defined. | ||
if (!map || !map[id] || map[id] + wait > Date.now()) { | ||
return; | ||
} | ||
delete map[id]; | ||
if (!Object.keys(map).length) { | ||
delete req.session._debounce; | ||
} | ||
// We need to save the session because request is possibly | ||
// already closed and session middleware will not do this for us. | ||
req.session.save(function(err) { | ||
if (err) fn(err); | ||
}); | ||
}); | ||
}, wait); | ||
}, wait + 10); | ||
} | ||
delete map[name]; | ||
if (!Object.keys(map).length) { | ||
delete req.session._debounce; | ||
} | ||
map[id] = Date.now(); | ||
req.session.save(fn); | ||
req.session.save(function(err) { | ||
if (err) fn(err); | ||
}); | ||
return id; | ||
} | ||
@@ -60,0 +88,0 @@ |
{ | ||
"name": "connect-debounce", | ||
"description": "Distributed debounced function execution ala underscore on per session basis as connect middleware.", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"author": "Oleg Slobodskoi <oleg008@gmail.com>", | ||
@@ -6,0 +6,0 @@ "repository": { |
@@ -13,3 +13,3 @@ ## Distributed debounced function execution ala underscore on per session basis as connect middleware. | ||
Module will save the date of the last attempt to execute the function into the session store of connect. On every attempt to execute it again, it will check the date and prevent execution more often than the `wait` time defined for the named function. | ||
Module will save the date of the last attempt to execute the function into the session store of connect. On every attempt to execute it again, it will check the date and prevent execution more often than the `wait` time defined for the function. | ||
@@ -34,6 +34,7 @@ ### Setup | ||
### req.debounce(fn:Function, [wait:Number]) | ||
### req.debounce(fn:Function, [wait:Number], [immediate:Boolean]) | ||
- `fn` is a named function which execution will be debounced. Its name is at the same time its unique identifier. It can get an error object passed as first argument. Don't ignore it! | ||
- `fn` is a function which execution will be debounced. It can get an error object passed as first argument. Don't ignore it! Better to use a function name to avoid potential conflicts with some other debounced function which has the same implementation. | ||
- `wait` time in ms to wait, default is the value described in setup. | ||
- `immediate` exec function immediately and debounce it later | ||
@@ -40,0 +41,0 @@ Example: |
110
test.js
@@ -45,7 +45,3 @@ QUnit.module('debounce'); | ||
req.debounce(); | ||
}, 'Named function required.'); | ||
throws(function() { | ||
req.debounce(function() {}); | ||
}, 'Named function required.'); | ||
}, 'Function required.'); | ||
}); | ||
@@ -58,5 +54,6 @@ | ||
scounter = 0, | ||
rcounter = 0; | ||
rcounter = 0, | ||
id; | ||
expect(6); | ||
expect(8); | ||
stop(); | ||
@@ -74,7 +71,6 @@ | ||
equal(typeof req.session._debounce, 'object', 'debounce store attached'); | ||
equal(typeof req.session._debounce.a, 'number', 'timestamp attached'); | ||
equal(typeof req.session._debounce[id], 'number', 'timestamp attached'); | ||
cb(); | ||
}; | ||
req.debounce(function a() { | ||
id = req.debounce(function() { | ||
dcounter++; | ||
@@ -85,10 +81,50 @@ }); | ||
equal(dcounter, 1, 'debounced function called only once'); | ||
equal(scounter, 2, 'session saved amount'); | ||
equal(scounter, 1, 'session saved amount'); | ||
equal(rcounter, 2, 'session reload amount'); | ||
equal(req.session._debounce, null, 'debounce map removed from session'); | ||
start(); | ||
}, 2050); | ||
}); | ||
test('debounce with immedaite=true', function() { | ||
var middleware = debounce(), | ||
req = getReq(), | ||
dcounter = 0, | ||
scounter = 0, | ||
rcounter = 0, | ||
id; | ||
expect(7); | ||
stop(); | ||
middleware(req, null, noop); | ||
req.session.save = function(cb) { | ||
scounter++; | ||
cb(); | ||
}; | ||
req.session.reload = function(cb) { | ||
rcounter++; | ||
equal(typeof req.session._debounce, 'object', 'debounce store attached'); | ||
equal(typeof req.session._debounce[id], 'number', 'timestamp attached'); | ||
cb(); | ||
}; | ||
id = req.debounce(function() { | ||
dcounter++; | ||
}, true); | ||
equal(dcounter, 1, 'debounced function called immediately'); | ||
setTimeout(function() { | ||
equal(dcounter, 1, 'debounced function called only once'); | ||
equal(scounter, 1, 'session saved amount'); | ||
equal(rcounter, 1, 'session reload amount'); | ||
equal(req.session._debounce, null, 'debounce map removed from session'); | ||
start(); | ||
}, 1100); | ||
}, 1020); | ||
}); | ||
test('debounce multiple', function() { | ||
test('debounce multiple times', function() { | ||
var middleware = debounce(), | ||
@@ -103,22 +139,50 @@ req = getReq(), | ||
req.debounce(function a() { | ||
function fn() { | ||
counter++; | ||
} | ||
req.debounce(fn, 2000); | ||
setTimeout(function() { | ||
req.debounce(fn, 2000); | ||
}, 1000); | ||
setTimeout(function() { | ||
req.debounce(fn, 2000); | ||
}, 2000); | ||
setTimeout(function() { | ||
req.debounce(function a() { | ||
counter++; | ||
}, 2000); | ||
}, 500); | ||
equal(counter, 1, 'debounced function called once'); | ||
start(); | ||
}, 5000); | ||
}); | ||
test('debounce multiple times with immediate=true', function() { | ||
var middleware = debounce(), | ||
req = getReq(), | ||
counter = 0; | ||
expect(1); | ||
stop(); | ||
middleware(req, null, noop); | ||
function fn() { | ||
counter++; | ||
} | ||
req.debounce(fn, 2000, true); | ||
setTimeout(function() { | ||
req.debounce(function a() { | ||
counter++; | ||
}, 2000); | ||
req.debounce(fn, 2000, true); | ||
}, 1000); | ||
setTimeout(function() { | ||
equal(counter, 1, 'debounced function called only once'); | ||
req.debounce(fn, 2000, true); | ||
}, 2000); | ||
setTimeout(function() { | ||
equal(counter, 2, 'debounced function called only once'); | ||
start(); | ||
}, 3100); | ||
}, 5000); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10972
216
63