1 | 'use strict';
|
2 |
|
3 | function throatInternal(size) {
|
4 | var queue = new Queue();
|
5 | var s = size | 0;
|
6 |
|
7 | function run(fn, self, args) {
|
8 | if ((s | 0) !== 0) {
|
9 | s = (s | 0) - 1;
|
10 | return new Promise(function (resolve) {
|
11 | resolve(fn.apply(self, args));
|
12 | }).then(onFulfill, onReject);
|
13 | }
|
14 | return new Promise(function (resolve) {
|
15 | queue.push(new Delayed(resolve, fn, self, args));
|
16 | }).then(runDelayed);
|
17 | }
|
18 | function runDelayed(d) {
|
19 | try {
|
20 | return Promise.resolve(d.fn.apply(d.self, d.args)).then(
|
21 | onFulfill,
|
22 | onReject
|
23 | );
|
24 | } catch (ex) {
|
25 | onReject(ex);
|
26 | }
|
27 | }
|
28 | function onFulfill(result) {
|
29 | release();
|
30 | return result;
|
31 | }
|
32 | function onReject(error) {
|
33 | release();
|
34 | throw error;
|
35 | }
|
36 | function release() {
|
37 | var next = queue.shift();
|
38 | if (next) {
|
39 | next.resolve(next);
|
40 | } else {
|
41 | s = (s | 0) + 1;
|
42 | }
|
43 | }
|
44 |
|
45 | return run;
|
46 | }
|
47 |
|
48 | function earlyBound(size, fn) {
|
49 | const run = throatInternal(size | 0);
|
50 | return function () {
|
51 | var args = new Array(arguments.length);
|
52 | for (var i = 0; i < arguments.length; i++) {
|
53 | args[i] = arguments[i];
|
54 | }
|
55 | return run(fn, this, args);
|
56 | };
|
57 | }
|
58 | function lateBound(size) {
|
59 | const run = throatInternal(size | 0);
|
60 | return function (fn) {
|
61 | if (typeof fn !== 'function') {
|
62 | throw new TypeError(
|
63 | 'Expected throat fn to be a function but got ' + typeof fn
|
64 | );
|
65 | }
|
66 | var args = new Array(arguments.length - 1);
|
67 | for (var i = 1; i < arguments.length; i++) {
|
68 | args[i - 1] = arguments[i];
|
69 | }
|
70 | return run(fn, this, args);
|
71 | };
|
72 | }
|
73 | module.exports = function throat(size, fn) {
|
74 | if (typeof size === 'function') {
|
75 | var temp = fn;
|
76 | fn = size;
|
77 | size = temp;
|
78 | }
|
79 | if (typeof size !== 'number') {
|
80 | throw new TypeError(
|
81 | 'Expected throat size to be a number but got ' + typeof size
|
82 | );
|
83 | }
|
84 | if (fn !== undefined && typeof fn !== 'function') {
|
85 | throw new TypeError(
|
86 | 'Expected throat fn to be a function but got ' + typeof fn
|
87 | );
|
88 | }
|
89 | if (typeof fn === 'function') {
|
90 | return earlyBound(size | 0, fn);
|
91 | } else {
|
92 | return lateBound(size | 0);
|
93 | }
|
94 | };
|
95 |
|
96 | module.exports.default = module.exports;
|
97 |
|
98 | function Delayed(resolve, fn, self, args) {
|
99 | this.resolve = resolve;
|
100 | this.fn = fn;
|
101 | this.self = self || null;
|
102 | this.args = args;
|
103 | }
|
104 |
|
105 | var blockSize = 64;
|
106 | function Queue() {
|
107 | this._s1 = [];
|
108 | this._s2 = [];
|
109 | this._shiftBlock = this._pushBlock = new Array(blockSize);
|
110 | this._pushIndex = 0;
|
111 | this._shiftIndex = 0;
|
112 | }
|
113 |
|
114 | Queue.prototype.push = function (value) {
|
115 | if (this._pushIndex === blockSize) {
|
116 | this._pushIndex = 0;
|
117 | this._s1[this._s1.length] = this._pushBlock = new Array(blockSize);
|
118 | }
|
119 | this._pushBlock[this._pushIndex++] = value;
|
120 | };
|
121 |
|
122 | Queue.prototype.shift = function () {
|
123 | if (this._shiftIndex === blockSize) {
|
124 | var s2 = this._s2;
|
125 | if (s2.length === 0) {
|
126 | var s1 = this._s1;
|
127 | if (s1.length === 0) {
|
128 | return undefined;
|
129 | }
|
130 | this._s1 = s2;
|
131 | s2 = this._s2 = s1.reverse();
|
132 | }
|
133 | this._shiftIndex = 0;
|
134 | this._shiftBlock = s2.pop();
|
135 | }
|
136 | if (
|
137 | this._pushBlock === this._shiftBlock &&
|
138 | this._pushIndex === this._shiftIndex
|
139 | ) {
|
140 | return undefined;
|
141 | }
|
142 | var result = this._shiftBlock[this._shiftIndex];
|
143 | this._shiftBlock[this._shiftIndex++] = null;
|
144 | return result;
|
145 | };
|