UNPKG

4.84 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
8
9var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
10
11var _promise = require('babel-runtime/core-js/promise');
12
13var _promise2 = _interopRequireDefault(_promise);
14
15var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
16
17var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
18
19var _createClass2 = require('babel-runtime/helpers/createClass');
20
21var _createClass3 = _interopRequireDefault(_createClass2);
22
23function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
25var debug = require('debug')('graphbrainz:rate-limit');
26
27var RateLimit = function () {
28 function RateLimit() {
29 var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
30 _ref$limit = _ref.limit,
31 limit = _ref$limit === undefined ? 1 : _ref$limit,
32 _ref$period = _ref.period,
33 period = _ref$period === undefined ? 1000 : _ref$period,
34 _ref$concurrency = _ref.concurrency,
35 concurrency = _ref$concurrency === undefined ? limit || 1 : _ref$concurrency,
36 _ref$defaultPriority = _ref.defaultPriority,
37 defaultPriority = _ref$defaultPriority === undefined ? 1 : _ref$defaultPriority;
38
39 (0, _classCallCheck3.default)(this, RateLimit);
40
41 this.limit = limit;
42 this.period = period;
43 this.defaultPriority = defaultPriority;
44 this.concurrency = concurrency;
45 this.queues = [];
46 this.numPending = 0;
47 this.periodStart = null;
48 this.periodCapacity = this.limit;
49 this.timer = null;
50 this.pendingFlush = false;
51 this.prevTaskID = null;
52 }
53
54 (0, _createClass3.default)(RateLimit, [{
55 key: 'nextTaskID',
56 value: function nextTaskID() {
57 var prevTaskID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.prevTaskID;
58
59 var id = (prevTaskID || 0) + 1;
60 this.prevTaskID = id;
61 return id;
62 }
63 }, {
64 key: 'enqueue',
65 value: function enqueue(fn, args) {
66 var _this = this;
67
68 var priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.defaultPriority;
69
70 priority = Math.max(0, priority);
71 return new _promise2.default(function (resolve, reject) {
72 var queue = _this.queues[priority] = _this.queues[priority] || [];
73 var id = _this.nextTaskID();
74 debug('Enqueuing task. id=' + id + ' priority=' + priority);
75 queue.push({ fn: fn, args: args, resolve: resolve, reject: reject, id: id });
76 if (!_this.pendingFlush) {
77 _this.pendingFlush = true;
78 process.nextTick(function () {
79 _this.pendingFlush = false;
80 _this.flush();
81 });
82 }
83 });
84 }
85 }, {
86 key: 'dequeue',
87 value: function dequeue() {
88 var task = void 0;
89 for (var i = this.queues.length - 1; i >= 0; i--) {
90 var queue = this.queues[i];
91 if (queue && queue.length) {
92 task = queue.shift();
93 }
94 if (!queue || !queue.length) {
95 this.queues.length = i;
96 }
97 if (task) {
98 break;
99 }
100 }
101 return task;
102 }
103 }, {
104 key: 'flush',
105 value: function flush() {
106 var _this2 = this;
107
108 if (this.numPending < this.concurrency && this.periodCapacity > 0) {
109 var task = this.dequeue();
110 if (task) {
111 var resolve = task.resolve,
112 reject = task.reject,
113 fn = task.fn,
114 args = task.args,
115 id = task.id;
116
117 if (this.timer == null) {
118 var now = Date.now();
119 var timeout = this.period;
120 if (this.periodStart != null) {
121 var delay = now - (this.periodStart + timeout);
122 if (delay > 0 && delay <= timeout) {
123 timeout -= delay;
124 }
125 }
126 this.periodStart = now;
127 this.timer = setTimeout(function () {
128 _this2.timer = null;
129 _this2.periodCapacity = _this2.limit;
130 _this2.flush();
131 }, timeout);
132 }
133 this.numPending += 1;
134 this.periodCapacity -= 1;
135 var onResolve = function onResolve(value) {
136 _this2.numPending -= 1;
137 resolve(value);
138 _this2.flush();
139 };
140 var onReject = function onReject(err) {
141 _this2.numPending -= 1;
142 reject(err);
143 _this2.flush();
144 };
145 debug('Running task. id=' + id);
146 fn.apply(undefined, (0, _toConsumableArray3.default)(args)).then(onResolve, onReject);
147 this.flush();
148 }
149 }
150 }
151 }]);
152 return RateLimit;
153}();
154
155exports.default = RateLimit;
\No newline at end of file