limit.js 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. "use strict";
  2. var ensureNaturalNumber = require("type/natural-number/ensure")
  3. , ensurePlainFunction = require("type/plain-function/ensure")
  4. , ensure = require("type/ensure")
  5. , defineFunctionLength = require("../lib/private/define-function-length");
  6. module.exports = function (limit, callback) {
  7. limit = ensure(
  8. ["limit", limit, ensureNaturalNumber, { min: 1 }],
  9. ["callback", callback, ensurePlainFunction]
  10. )[0];
  11. var Promise = this, ongoingCount = 0, pending = [];
  12. var onSuccess, onFailure;
  13. var release = function () {
  14. --ongoingCount;
  15. if (ongoingCount >= limit) return;
  16. var next = pending.shift();
  17. if (!next) return;
  18. ++ongoingCount;
  19. try {
  20. next.resolve(
  21. Promise.resolve(callback.apply(next.context, next.arguments)).then(
  22. onSuccess, onFailure
  23. )
  24. );
  25. } catch (exception) {
  26. release();
  27. next.reject(exception);
  28. }
  29. };
  30. onSuccess = function (value) {
  31. release();
  32. return value;
  33. };
  34. onFailure = function (exception) {
  35. release();
  36. throw exception;
  37. };
  38. return defineFunctionLength(callback.length, function () {
  39. if (ongoingCount >= limit) {
  40. var context = this, args = arguments;
  41. return new Promise(function (resolve, reject) {
  42. pending.push({
  43. context: context,
  44. arguments: args,
  45. resolve: resolve,
  46. reject: reject
  47. });
  48. });
  49. }
  50. ++ongoingCount;
  51. try {
  52. return Promise.resolve(callback.apply(this, arguments)).then(onSuccess, onFailure);
  53. } catch (exception) { return onFailure(exception); }
  54. });
  55. };