1 |
|
2 |
|
3 |
|
4 | function findIndex(array, predicate) {
|
5 | for (var i = 0; i < array.length; i++) {
|
6 | if (predicate(array[i])) return i;
|
7 | }
|
8 |
|
9 | return -1;
|
10 | }
|
11 |
|
12 | function createCancelError() {
|
13 | return new Error('Cancelled');
|
14 | }
|
15 |
|
16 | module.exports = function () {
|
17 | function RateLimitedQueue(limit) {
|
18 | if (typeof limit !== 'number' || limit === 0) {
|
19 | this.limit = Infinity;
|
20 | } else {
|
21 | this.limit = limit;
|
22 | }
|
23 |
|
24 | this.activeRequests = 0;
|
25 | this.queuedHandlers = [];
|
26 | }
|
27 |
|
28 | var _proto = RateLimitedQueue.prototype;
|
29 |
|
30 | _proto._call = function _call(fn) {
|
31 | var _this = this;
|
32 |
|
33 | this.activeRequests += 1;
|
34 | var _done = false;
|
35 | var cancelActive;
|
36 |
|
37 | try {
|
38 | cancelActive = fn();
|
39 | } catch (err) {
|
40 | this.activeRequests -= 1;
|
41 | throw err;
|
42 | }
|
43 |
|
44 | return {
|
45 | abort: function abort() {
|
46 | if (_done) return;
|
47 | _done = true;
|
48 | _this.activeRequests -= 1;
|
49 | cancelActive();
|
50 |
|
51 | _this._queueNext();
|
52 | },
|
53 | done: function done() {
|
54 | if (_done) return;
|
55 | _done = true;
|
56 | _this.activeRequests -= 1;
|
57 |
|
58 | _this._queueNext();
|
59 | }
|
60 | };
|
61 | };
|
62 |
|
63 | _proto._queueNext = function _queueNext() {
|
64 | var _this2 = this;
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | Promise.resolve().then(function () {
|
70 | _this2._next();
|
71 | });
|
72 | };
|
73 |
|
74 | _proto._next = function _next() {
|
75 | if (this.activeRequests >= this.limit) {
|
76 | return;
|
77 | }
|
78 |
|
79 | if (this.queuedHandlers.length === 0) {
|
80 | return;
|
81 | }
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | var next = this.queuedHandlers.shift();
|
87 |
|
88 | var handler = this._call(next.fn);
|
89 |
|
90 | next.abort = handler.abort;
|
91 | next.done = handler.done;
|
92 | };
|
93 |
|
94 | _proto._queue = function _queue(fn, options) {
|
95 | var _this3 = this;
|
96 |
|
97 | if (options === void 0) {
|
98 | options = {};
|
99 | }
|
100 |
|
101 | var handler = {
|
102 | fn: fn,
|
103 | priority: options.priority || 0,
|
104 | abort: function abort() {
|
105 | _this3._dequeue(handler);
|
106 | },
|
107 | done: function done() {
|
108 | throw new Error('Cannot mark a queued request as done: this indicates a bug');
|
109 | }
|
110 | };
|
111 | var index = findIndex(this.queuedHandlers, function (other) {
|
112 | return handler.priority > other.priority;
|
113 | });
|
114 |
|
115 | if (index === -1) {
|
116 | this.queuedHandlers.push(handler);
|
117 | } else {
|
118 | this.queuedHandlers.splice(index, 0, handler);
|
119 | }
|
120 |
|
121 | return handler;
|
122 | };
|
123 |
|
124 | _proto._dequeue = function _dequeue(handler) {
|
125 | var index = this.queuedHandlers.indexOf(handler);
|
126 |
|
127 | if (index !== -1) {
|
128 | this.queuedHandlers.splice(index, 1);
|
129 | }
|
130 | };
|
131 |
|
132 | _proto.run = function run(fn, queueOptions) {
|
133 | if (this.activeRequests < this.limit) {
|
134 | return this._call(fn);
|
135 | }
|
136 |
|
137 | return this._queue(fn, queueOptions);
|
138 | };
|
139 |
|
140 | _proto.wrapPromiseFunction = function wrapPromiseFunction(fn, queueOptions) {
|
141 | var _this4 = this;
|
142 |
|
143 | return function () {
|
144 | for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
145 | args[_key] = arguments[_key];
|
146 | }
|
147 |
|
148 | var queuedRequest;
|
149 | var outerPromise = new Promise(function (resolve, reject) {
|
150 | queuedRequest = _this4.run(function () {
|
151 | var cancelError;
|
152 | var innerPromise;
|
153 |
|
154 | try {
|
155 | innerPromise = Promise.resolve(fn.apply(void 0, args));
|
156 | } catch (err) {
|
157 | innerPromise = Promise.reject(err);
|
158 | }
|
159 |
|
160 | innerPromise.then(function (result) {
|
161 | if (cancelError) {
|
162 | reject(cancelError);
|
163 | } else {
|
164 | queuedRequest.done();
|
165 | resolve(result);
|
166 | }
|
167 | }, function (err) {
|
168 | if (cancelError) {
|
169 | reject(cancelError);
|
170 | } else {
|
171 | queuedRequest.done();
|
172 | reject(err);
|
173 | }
|
174 | });
|
175 | return function () {
|
176 | cancelError = createCancelError();
|
177 | };
|
178 | }, queueOptions);
|
179 | });
|
180 |
|
181 | outerPromise.abort = function () {
|
182 | queuedRequest.abort();
|
183 | };
|
184 |
|
185 | return outerPromise;
|
186 | };
|
187 | };
|
188 |
|
189 | return RateLimitedQueue;
|
190 | }(); |
\ | No newline at end of file |