| 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 | };
|
|---|