guard.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. /** @license MIT License (c) copyright 2011-2013 original author or authors */
  2. /**
  3. * Generalized promise concurrency guard
  4. * Adapted from original concept by Sakari Jokinen (Rocket Pack, Ltd.)
  5. *
  6. * @author Brian Cavalier
  7. * @author John Hann
  8. * @contributor Sakari Jokinen
  9. */
  10. (function(define) {
  11. define(function(require) {
  12. var when = require('./when');
  13. var slice = Array.prototype.slice;
  14. guard.n = n;
  15. return guard;
  16. /**
  17. * Creates a guarded version of f that can only be entered when the supplied
  18. * condition allows.
  19. * @param {function} condition represents a critical section that may only
  20. * be entered when allowed by the condition
  21. * @param {function} f function to guard
  22. * @returns {function} guarded version of f
  23. */
  24. function guard(condition, f) {
  25. return function() {
  26. var args = slice.call(arguments);
  27. return when(condition()).withThis(this).then(function(exit) {
  28. return when(f.apply(this, args))['finally'](exit);
  29. });
  30. };
  31. }
  32. /**
  33. * Creates a condition that allows only n simultaneous executions
  34. * of a guarded function
  35. * @param {number} allowed number of allowed simultaneous executions
  36. * @returns {function} condition function which returns a promise that
  37. * fulfills when the critical section may be entered. The fulfillment
  38. * value is a function ("notifyExit") that must be called when the critical
  39. * section has been exited.
  40. */
  41. function n(allowed) {
  42. var count = 0;
  43. var waiting = [];
  44. return function enter() {
  45. return when.promise(function(resolve) {
  46. if(count < allowed) {
  47. resolve(exit);
  48. } else {
  49. waiting.push(resolve);
  50. }
  51. count += 1;
  52. });
  53. };
  54. function exit() {
  55. count = Math.max(count - 1, 0);
  56. if(waiting.length > 0) {
  57. waiting.shift()(exit);
  58. }
  59. }
  60. }
  61. });
  62. }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));