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