chenyc
2025-12-09 65e034683b28d799e73c7d7e5e4769fab5b9bc9c
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
"use strict";
 
var ensureNaturalNumber  = require("type/natural-number/ensure")
  , ensurePlainFunction  = require("type/plain-function/ensure")
  , ensure               = require("type/ensure")
  , defineFunctionLength = require("../lib/private/define-function-length");
 
module.exports = function (limit, callback) {
    limit = ensure(
        ["limit", limit, ensureNaturalNumber, { min: 1 }],
        ["callback", callback, ensurePlainFunction]
    )[0];
 
    var Promise = this, ongoingCount = 0, pending = [];
    var onSuccess, onFailure;
 
    var release = function () {
        --ongoingCount;
        if (ongoingCount >= limit) return;
        var next = pending.shift();
        if (!next) return;
        ++ongoingCount;
        try {
            next.resolve(
                Promise.resolve(callback.apply(next.context, next.arguments)).then(
                    onSuccess, onFailure
                )
            );
        } catch (exception) {
            release();
            next.reject(exception);
        }
    };
 
    onSuccess = function (value) {
        release();
        return value;
    };
 
    onFailure = function (exception) {
        release();
        throw exception;
    };
 
    return defineFunctionLength(callback.length, function () {
        if (ongoingCount >= limit) {
            var context = this, args = arguments;
            return new Promise(function (resolve, reject) {
                pending.push({
                    context: context,
                    arguments: args,
                    resolve: resolve,
                    reject: reject
                });
            });
        }
        ++ongoingCount;
        try {
            return Promise.resolve(callback.apply(this, arguments)).then(onSuccess, onFailure);
        } catch (exception) { return onFailure(exception); }
    });
};