@loaders.gl/loader-utils 4.1.3 → 4.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +16 -7
- package/dist/json-loader.js +1 -1
- package/dist/lib/request-utils/request-scheduler.d.ts +2 -1
- package/dist/lib/request-utils/request-scheduler.d.ts.map +1 -1
- package/dist/lib/request-utils/request-scheduler.js +10 -5
- package/dist/lib/request-utils/request-scheduler.js.map +1 -1
- package/package.json +3 -3
- package/src/lib/request-utils/request-scheduler.ts +17 -8
package/dist/index.cjs
CHANGED
|
@@ -531,10 +531,15 @@ var STAT_QUEUED_REQUESTS_EVER = "Queued Requests Ever";
|
|
|
531
531
|
var STAT_ACTIVE_REQUESTS_EVER = "Active Requests Ever";
|
|
532
532
|
var DEFAULT_PROPS = {
|
|
533
533
|
id: "request-scheduler",
|
|
534
|
-
|
|
534
|
+
/** Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing. */
|
|
535
535
|
throttleRequests: true,
|
|
536
|
-
|
|
537
|
-
maxRequests: 6
|
|
536
|
+
/** The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit. */
|
|
537
|
+
maxRequests: 6,
|
|
538
|
+
/**
|
|
539
|
+
* Specifies a debounce time, in milliseconds. All requests are queued, until no new requests have
|
|
540
|
+
* been added to the queue for this amount of time.
|
|
541
|
+
*/
|
|
542
|
+
debounceTime: 0
|
|
538
543
|
};
|
|
539
544
|
var RequestScheduler = class {
|
|
540
545
|
constructor(props = {}) {
|
|
@@ -542,7 +547,7 @@ var RequestScheduler = class {
|
|
|
542
547
|
/** Tracks the number of active requests and prioritizes/cancels queued requests. */
|
|
543
548
|
this.requestQueue = [];
|
|
544
549
|
this.requestMap = /* @__PURE__ */ new Map();
|
|
545
|
-
this.
|
|
550
|
+
this.updateTimer = null;
|
|
546
551
|
this.props = { ...DEFAULT_PROPS, ...props };
|
|
547
552
|
this.stats = new import_stats.Stats({ id: this.props.id });
|
|
548
553
|
this.stats.get(STAT_QUEUED_REQUESTS);
|
|
@@ -602,13 +607,17 @@ var RequestScheduler = class {
|
|
|
602
607
|
}
|
|
603
608
|
/** We check requests asynchronously, to prevent multiple updates */
|
|
604
609
|
_issueNewRequests() {
|
|
605
|
-
if (
|
|
606
|
-
|
|
610
|
+
if (this.updateTimer !== null) {
|
|
611
|
+
clearTimeout(this.updateTimer);
|
|
607
612
|
}
|
|
613
|
+
this.updateTimer = setTimeout(() => this._issueNewRequestsAsync(), this.props.debounceTime);
|
|
608
614
|
}
|
|
609
615
|
/** Refresh all requests */
|
|
610
616
|
_issueNewRequestsAsync() {
|
|
611
|
-
this.
|
|
617
|
+
if (this.updateTimer !== null) {
|
|
618
|
+
clearTimeout(this.updateTimer);
|
|
619
|
+
}
|
|
620
|
+
this.updateTimer = null;
|
|
612
621
|
const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);
|
|
613
622
|
if (freeSlots === 0) {
|
|
614
623
|
return;
|
package/dist/json-loader.js
CHANGED
|
@@ -10,6 +10,7 @@ export type RequestSchedulerProps = {
|
|
|
10
10
|
id?: string;
|
|
11
11
|
throttleRequests?: boolean;
|
|
12
12
|
maxRequests?: number;
|
|
13
|
+
debounceTime?: number;
|
|
13
14
|
};
|
|
14
15
|
/** Tracks one request */
|
|
15
16
|
type Request = {
|
|
@@ -29,7 +30,7 @@ export default class RequestScheduler {
|
|
|
29
30
|
/** Tracks the number of active requests and prioritizes/cancels queued requests. */
|
|
30
31
|
private requestQueue;
|
|
31
32
|
private requestMap;
|
|
32
|
-
private
|
|
33
|
+
private updateTimer;
|
|
33
34
|
constructor(props?: RequestSchedulerProps);
|
|
34
35
|
/**
|
|
35
36
|
* Called by an application that wants to issue a request, without having it deeply queued by the browser
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-scheduler.d.ts","sourceRoot":"","sources":["../../../src/lib/request-utils/request-scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAEtC,KAAK,MAAM,GAAG,GAAG,CAAC;AAClB,KAAK,YAAY,GAAG,MAAM,GAAG,CAAC;AAC9B,KAAK,mBAAmB,GAAG,MAAM,MAAM,CAAC;AACxC,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,YAAY,CAAC;CACpB,GAAG,IAAI,CAAC;AAET,+BAA+B;AAC/B,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"request-scheduler.d.ts","sourceRoot":"","sources":["../../../src/lib/request-utils/request-scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAEtC,KAAK,MAAM,GAAG,GAAG,CAAC;AAClB,KAAK,YAAY,GAAG,MAAM,GAAG,CAAC;AAC9B,KAAK,mBAAmB,GAAG,MAAM,MAAM,CAAC;AACxC,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,YAAY,CAAC;CACpB,GAAG,IAAI,CAAC;AAET,+BAA+B;AAC/B,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAqBF,yBAAyB;AACzB,KAAK,OAAO,GAAG;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,mBAAmB,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAK;IAE/B,oFAAoF;IACpF,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,UAAU,CAAkD;IACpE,OAAO,CAAC,WAAW,CAA8C;gBAErD,KAAK,GAAE,qBAA0B;IAY7C;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CACb,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,mBAA6B,GACzC,OAAO,CAAC,aAAa,CAAC;IA0BzB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;IAuB7C,oEAAoE;IACpE,iBAAiB,IAAI,IAAI;IAOzB,4BAA4B;IAC5B,sBAAsB;IA0BtB,mGAAmG;IACnG,kBAAkB;IAgBlB,sDAAsD;IACtD,cAAc,CAAC,OAAO,KAAA;CAUvB"}
|
|
@@ -7,7 +7,8 @@ const STAT_ACTIVE_REQUESTS_EVER = 'Active Requests Ever';
|
|
|
7
7
|
const DEFAULT_PROPS = {
|
|
8
8
|
id: 'request-scheduler',
|
|
9
9
|
throttleRequests: true,
|
|
10
|
-
maxRequests: 6
|
|
10
|
+
maxRequests: 6,
|
|
11
|
+
debounceTime: 0
|
|
11
12
|
};
|
|
12
13
|
export default class RequestScheduler {
|
|
13
14
|
constructor() {
|
|
@@ -17,7 +18,7 @@ export default class RequestScheduler {
|
|
|
17
18
|
this.activeRequestCount = 0;
|
|
18
19
|
this.requestQueue = [];
|
|
19
20
|
this.requestMap = new Map();
|
|
20
|
-
this.
|
|
21
|
+
this.updateTimer = null;
|
|
21
22
|
this.props = {
|
|
22
23
|
...DEFAULT_PROPS,
|
|
23
24
|
...props
|
|
@@ -77,12 +78,16 @@ export default class RequestScheduler {
|
|
|
77
78
|
});
|
|
78
79
|
}
|
|
79
80
|
_issueNewRequests() {
|
|
80
|
-
if (
|
|
81
|
-
|
|
81
|
+
if (this.updateTimer !== null) {
|
|
82
|
+
clearTimeout(this.updateTimer);
|
|
82
83
|
}
|
|
84
|
+
this.updateTimer = setTimeout(() => this._issueNewRequestsAsync(), this.props.debounceTime);
|
|
83
85
|
}
|
|
84
86
|
_issueNewRequestsAsync() {
|
|
85
|
-
this.
|
|
87
|
+
if (this.updateTimer !== null) {
|
|
88
|
+
clearTimeout(this.updateTimer);
|
|
89
|
+
}
|
|
90
|
+
this.updateTimer = null;
|
|
86
91
|
const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);
|
|
87
92
|
if (freeSlots === 0) {
|
|
88
93
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-scheduler.js","names":["Stats","STAT_QUEUED_REQUESTS","STAT_ACTIVE_REQUESTS","STAT_CANCELLED_REQUESTS","STAT_QUEUED_REQUESTS_EVER","STAT_ACTIVE_REQUESTS_EVER","DEFAULT_PROPS","id","throttleRequests","maxRequests","RequestScheduler","constructor","props","arguments","length","undefined","stats","activeRequestCount","requestQueue","requestMap","Map","deferredUpdate","get","scheduleRequest","handle","getPriority","Promise","resolve","done","has","request","priority","promise","push","set","_issueNewRequests","_issueRequest","isDone","delete","setTimeout","_issueNewRequestsAsync","freeSlots","Math","max","_updateAllRequests","i","shift","_updateRequest","splice","sort","a","b"],"sources":["../../../src/lib/request-utils/request-scheduler.ts"],"sourcesContent":["import {Stats} from '@probe.gl/stats';\n\ntype Handle = any;\ntype DoneFunction = () => any;\ntype GetPriorityFunction = () => number;\ntype RequestResult = {\n done: DoneFunction;\n} | null;\n\n/** RequestScheduler Options */\nexport type RequestSchedulerProps = {\n id?: string;\n throttleRequests?: boolean;\n maxRequests?: number;\n};\n\nconst STAT_QUEUED_REQUESTS = 'Queued Requests';\nconst STAT_ACTIVE_REQUESTS = 'Active Requests';\nconst STAT_CANCELLED_REQUESTS = 'Cancelled Requests';\nconst STAT_QUEUED_REQUESTS_EVER = 'Queued Requests Ever';\nconst STAT_ACTIVE_REQUESTS_EVER = 'Active Requests Ever';\n\nconst DEFAULT_PROPS: Required<RequestSchedulerProps> = {\n id: 'request-scheduler',\n // Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing\n throttleRequests: true,\n // The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit.\n maxRequests: 6\n};\n\n/** Tracks one request */\ntype Request = {\n handle: Handle;\n priority: number;\n getPriority: GetPriorityFunction;\n resolve?: (value: any) => any;\n};\n\n/**\n * Used to issue a request, without having them \"deeply queued\" by the browser.\n * @todo - Track requests globally, across multiple servers\n */\nexport default class RequestScheduler {\n readonly props: Required<RequestSchedulerProps>;\n readonly stats: Stats;\n activeRequestCount: number = 0;\n\n /** Tracks the number of active requests and prioritizes/cancels queued requests. */\n private requestQueue: Request[] = [];\n private requestMap: Map<Handle, Promise<RequestResult>> = new Map();\n private deferredUpdate: any = null;\n\n constructor(props: RequestSchedulerProps = {}) {\n this.props = {...DEFAULT_PROPS, ...props};\n\n // Returns the statistics used by the request scheduler.\n this.stats = new Stats({id: this.props.id});\n this.stats.get(STAT_QUEUED_REQUESTS);\n this.stats.get(STAT_ACTIVE_REQUESTS);\n this.stats.get(STAT_CANCELLED_REQUESTS);\n this.stats.get(STAT_QUEUED_REQUESTS_EVER);\n this.stats.get(STAT_ACTIVE_REQUESTS_EVER);\n }\n\n /**\n * Called by an application that wants to issue a request, without having it deeply queued by the browser\n *\n * When the returned promise resolved, it is OK for the application to issue a request.\n * The promise resolves to an object that contains a `done` method.\n * When the application's request has completed (or failed), the application must call the `done` function\n *\n * @param handle\n * @param getPriority will be called when request \"slots\" open up,\n * allowing the caller to update priority or cancel the request\n * Highest priority executes first, priority < 0 cancels the request\n * @returns a promise\n * - resolves to a object (with a `done` field) when the request can be issued without queueing,\n * - resolves to `null` if the request has been cancelled (by the callback return < 0).\n * In this case the application should not issue the request\n */\n scheduleRequest(\n handle: Handle,\n getPriority: GetPriorityFunction = () => 0\n ): Promise<RequestResult> {\n // Allows throttling to be disabled\n if (!this.props.throttleRequests) {\n return Promise.resolve({done: () => {}});\n }\n\n // dedupe\n if (this.requestMap.has(handle)) {\n return this.requestMap.get(handle) as Promise<any>;\n }\n\n const request: Request = {handle, priority: 0, getPriority};\n const promise = new Promise<RequestResult>((resolve) => {\n // @ts-ignore\n request.resolve = resolve;\n return request;\n });\n\n this.requestQueue.push(request);\n this.requestMap.set(handle, promise);\n this._issueNewRequests();\n return promise;\n }\n\n // PRIVATE\n\n _issueRequest(request: Request): Promise<any> {\n const {handle, resolve} = request;\n let isDone = false;\n\n const done = () => {\n // can only be called once\n if (!isDone) {\n isDone = true;\n\n // Stop tracking a request - it has completed, failed, cancelled etc\n this.requestMap.delete(handle);\n this.activeRequestCount--;\n // A slot just freed up, see if any queued requests are waiting\n this._issueNewRequests();\n }\n };\n\n // Track this request\n this.activeRequestCount++;\n\n return resolve ? resolve({done}) : Promise.resolve({done});\n }\n\n /** We check requests asynchronously, to prevent multiple updates */\n _issueNewRequests(): void {\n if (!this.deferredUpdate) {\n this.deferredUpdate = setTimeout(() => this._issueNewRequestsAsync(), 0);\n }\n }\n\n /** Refresh all requests */\n _issueNewRequestsAsync() {\n // TODO - shouldn't we clear the timeout?\n this.deferredUpdate = null;\n\n const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);\n\n if (freeSlots === 0) {\n return;\n }\n\n this._updateAllRequests();\n\n // Resolve pending promises for the top-priority requests\n for (let i = 0; i < freeSlots; ++i) {\n const request = this.requestQueue.shift();\n if (request) {\n this._issueRequest(request); // eslint-disable-line @typescript-eslint/no-floating-promises\n }\n }\n\n // Uncomment to debug\n // console.log(`${freeSlots} free slots, ${this.requestQueue.length} queued requests`);\n }\n\n /** Ensure all requests have updated priorities, and that no longer valid requests are cancelled */\n _updateAllRequests() {\n const requestQueue = this.requestQueue;\n for (let i = 0; i < requestQueue.length; ++i) {\n const request = requestQueue[i];\n if (!this._updateRequest(request)) {\n // Remove the element and make sure to adjust the counter to account for shortened array\n requestQueue.splice(i, 1);\n this.requestMap.delete(request.handle);\n i--;\n }\n }\n\n // Sort the remaining requests based on priority\n requestQueue.sort((a, b) => a.priority - b.priority);\n }\n\n /** Update a single request by calling the callback */\n _updateRequest(request) {\n request.priority = request.getPriority(request.handle); // eslint-disable-line callback-return\n\n // by returning a negative priority, the callback cancels the request\n if (request.priority < 0) {\n request.resolve(null);\n return false;\n }\n return true;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request-scheduler.js","names":["Stats","STAT_QUEUED_REQUESTS","STAT_ACTIVE_REQUESTS","STAT_CANCELLED_REQUESTS","STAT_QUEUED_REQUESTS_EVER","STAT_ACTIVE_REQUESTS_EVER","DEFAULT_PROPS","id","throttleRequests","maxRequests","debounceTime","RequestScheduler","constructor","props","arguments","length","undefined","stats","activeRequestCount","requestQueue","requestMap","Map","updateTimer","get","scheduleRequest","handle","getPriority","Promise","resolve","done","has","request","priority","promise","push","set","_issueNewRequests","_issueRequest","isDone","delete","clearTimeout","setTimeout","_issueNewRequestsAsync","freeSlots","Math","max","_updateAllRequests","i","shift","_updateRequest","splice","sort","a","b"],"sources":["../../../src/lib/request-utils/request-scheduler.ts"],"sourcesContent":["import {Stats} from '@probe.gl/stats';\n\ntype Handle = any;\ntype DoneFunction = () => any;\ntype GetPriorityFunction = () => number;\ntype RequestResult = {\n done: DoneFunction;\n} | null;\n\n/** RequestScheduler Options */\nexport type RequestSchedulerProps = {\n id?: string;\n throttleRequests?: boolean;\n maxRequests?: number;\n debounceTime?: number;\n};\n\nconst STAT_QUEUED_REQUESTS = 'Queued Requests';\nconst STAT_ACTIVE_REQUESTS = 'Active Requests';\nconst STAT_CANCELLED_REQUESTS = 'Cancelled Requests';\nconst STAT_QUEUED_REQUESTS_EVER = 'Queued Requests Ever';\nconst STAT_ACTIVE_REQUESTS_EVER = 'Active Requests Ever';\n\nconst DEFAULT_PROPS: Required<RequestSchedulerProps> = {\n id: 'request-scheduler',\n /** Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing. */\n throttleRequests: true,\n /** The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit. */\n maxRequests: 6,\n /**\n * Specifies a debounce time, in milliseconds. All requests are queued, until no new requests have\n * been added to the queue for this amount of time.\n */\n debounceTime: 0\n};\n\n/** Tracks one request */\ntype Request = {\n handle: Handle;\n priority: number;\n getPriority: GetPriorityFunction;\n resolve?: (value: any) => any;\n};\n\n/**\n * Used to issue a request, without having them \"deeply queued\" by the browser.\n * @todo - Track requests globally, across multiple servers\n */\nexport default class RequestScheduler {\n readonly props: Required<RequestSchedulerProps>;\n readonly stats: Stats;\n activeRequestCount: number = 0;\n\n /** Tracks the number of active requests and prioritizes/cancels queued requests. */\n private requestQueue: Request[] = [];\n private requestMap: Map<Handle, Promise<RequestResult>> = new Map();\n private updateTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(props: RequestSchedulerProps = {}) {\n this.props = {...DEFAULT_PROPS, ...props};\n\n // Returns the statistics used by the request scheduler.\n this.stats = new Stats({id: this.props.id});\n this.stats.get(STAT_QUEUED_REQUESTS);\n this.stats.get(STAT_ACTIVE_REQUESTS);\n this.stats.get(STAT_CANCELLED_REQUESTS);\n this.stats.get(STAT_QUEUED_REQUESTS_EVER);\n this.stats.get(STAT_ACTIVE_REQUESTS_EVER);\n }\n\n /**\n * Called by an application that wants to issue a request, without having it deeply queued by the browser\n *\n * When the returned promise resolved, it is OK for the application to issue a request.\n * The promise resolves to an object that contains a `done` method.\n * When the application's request has completed (or failed), the application must call the `done` function\n *\n * @param handle\n * @param getPriority will be called when request \"slots\" open up,\n * allowing the caller to update priority or cancel the request\n * Highest priority executes first, priority < 0 cancels the request\n * @returns a promise\n * - resolves to a object (with a `done` field) when the request can be issued without queueing,\n * - resolves to `null` if the request has been cancelled (by the callback return < 0).\n * In this case the application should not issue the request\n */\n scheduleRequest(\n handle: Handle,\n getPriority: GetPriorityFunction = () => 0\n ): Promise<RequestResult> {\n // Allows throttling to be disabled\n if (!this.props.throttleRequests) {\n return Promise.resolve({done: () => {}});\n }\n\n // dedupe\n if (this.requestMap.has(handle)) {\n return this.requestMap.get(handle) as Promise<any>;\n }\n\n const request: Request = {handle, priority: 0, getPriority};\n const promise = new Promise<RequestResult>((resolve) => {\n // @ts-ignore\n request.resolve = resolve;\n return request;\n });\n\n this.requestQueue.push(request);\n this.requestMap.set(handle, promise);\n this._issueNewRequests();\n return promise;\n }\n\n // PRIVATE\n\n _issueRequest(request: Request): Promise<any> {\n const {handle, resolve} = request;\n let isDone = false;\n\n const done = () => {\n // can only be called once\n if (!isDone) {\n isDone = true;\n\n // Stop tracking a request - it has completed, failed, cancelled etc\n this.requestMap.delete(handle);\n this.activeRequestCount--;\n // A slot just freed up, see if any queued requests are waiting\n this._issueNewRequests();\n }\n };\n\n // Track this request\n this.activeRequestCount++;\n\n return resolve ? resolve({done}) : Promise.resolve({done});\n }\n\n /** We check requests asynchronously, to prevent multiple updates */\n _issueNewRequests(): void {\n if (this.updateTimer !== null) {\n clearTimeout(this.updateTimer);\n }\n this.updateTimer = setTimeout(() => this._issueNewRequestsAsync(), this.props.debounceTime);\n }\n\n /** Refresh all requests */\n _issueNewRequestsAsync() {\n if (this.updateTimer !== null) {\n clearTimeout(this.updateTimer);\n }\n this.updateTimer = null;\n\n const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);\n\n if (freeSlots === 0) {\n return;\n }\n\n this._updateAllRequests();\n\n // Resolve pending promises for the top-priority requests\n for (let i = 0; i < freeSlots; ++i) {\n const request = this.requestQueue.shift();\n if (request) {\n this._issueRequest(request); // eslint-disable-line @typescript-eslint/no-floating-promises\n }\n }\n\n // Uncomment to debug\n // console.log(`${freeSlots} free slots, ${this.requestQueue.length} queued requests`);\n }\n\n /** Ensure all requests have updated priorities, and that no longer valid requests are cancelled */\n _updateAllRequests() {\n const requestQueue = this.requestQueue;\n for (let i = 0; i < requestQueue.length; ++i) {\n const request = requestQueue[i];\n if (!this._updateRequest(request)) {\n // Remove the element and make sure to adjust the counter to account for shortened array\n requestQueue.splice(i, 1);\n this.requestMap.delete(request.handle);\n i--;\n }\n }\n\n // Sort the remaining requests based on priority\n requestQueue.sort((a, b) => a.priority - b.priority);\n }\n\n /** Update a single request by calling the callback */\n _updateRequest(request) {\n request.priority = request.getPriority(request.handle); // eslint-disable-line callback-return\n\n // by returning a negative priority, the callback cancels the request\n if (request.priority < 0) {\n request.resolve(null);\n return false;\n }\n return true;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loaders.gl/loader-utils",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
4
4
|
"description": "Framework-independent loaders for 3D graphics formats",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"scripts": {},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@babel/runtime": "^7.3.1",
|
|
50
|
-
"@loaders.gl/worker-utils": "4.1.
|
|
50
|
+
"@loaders.gl/worker-utils": "4.1.4",
|
|
51
51
|
"@probe.gl/stats": "^4.0.2"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "e5b4fe1845c1483addfc4c3d630f1617595efbae"
|
|
54
54
|
}
|
|
@@ -12,6 +12,7 @@ export type RequestSchedulerProps = {
|
|
|
12
12
|
id?: string;
|
|
13
13
|
throttleRequests?: boolean;
|
|
14
14
|
maxRequests?: number;
|
|
15
|
+
debounceTime?: number;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const STAT_QUEUED_REQUESTS = 'Queued Requests';
|
|
@@ -22,10 +23,15 @@ const STAT_ACTIVE_REQUESTS_EVER = 'Active Requests Ever';
|
|
|
22
23
|
|
|
23
24
|
const DEFAULT_PROPS: Required<RequestSchedulerProps> = {
|
|
24
25
|
id: 'request-scheduler',
|
|
25
|
-
|
|
26
|
+
/** Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing. */
|
|
26
27
|
throttleRequests: true,
|
|
27
|
-
|
|
28
|
-
maxRequests: 6
|
|
28
|
+
/** The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit. */
|
|
29
|
+
maxRequests: 6,
|
|
30
|
+
/**
|
|
31
|
+
* Specifies a debounce time, in milliseconds. All requests are queued, until no new requests have
|
|
32
|
+
* been added to the queue for this amount of time.
|
|
33
|
+
*/
|
|
34
|
+
debounceTime: 0
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
/** Tracks one request */
|
|
@@ -48,7 +54,7 @@ export default class RequestScheduler {
|
|
|
48
54
|
/** Tracks the number of active requests and prioritizes/cancels queued requests. */
|
|
49
55
|
private requestQueue: Request[] = [];
|
|
50
56
|
private requestMap: Map<Handle, Promise<RequestResult>> = new Map();
|
|
51
|
-
private
|
|
57
|
+
private updateTimer: ReturnType<typeof setTimeout> | null = null;
|
|
52
58
|
|
|
53
59
|
constructor(props: RequestSchedulerProps = {}) {
|
|
54
60
|
this.props = {...DEFAULT_PROPS, ...props};
|
|
@@ -132,15 +138,18 @@ export default class RequestScheduler {
|
|
|
132
138
|
|
|
133
139
|
/** We check requests asynchronously, to prevent multiple updates */
|
|
134
140
|
_issueNewRequests(): void {
|
|
135
|
-
if (
|
|
136
|
-
|
|
141
|
+
if (this.updateTimer !== null) {
|
|
142
|
+
clearTimeout(this.updateTimer);
|
|
137
143
|
}
|
|
144
|
+
this.updateTimer = setTimeout(() => this._issueNewRequestsAsync(), this.props.debounceTime);
|
|
138
145
|
}
|
|
139
146
|
|
|
140
147
|
/** Refresh all requests */
|
|
141
148
|
_issueNewRequestsAsync() {
|
|
142
|
-
|
|
143
|
-
|
|
149
|
+
if (this.updateTimer !== null) {
|
|
150
|
+
clearTimeout(this.updateTimer);
|
|
151
|
+
}
|
|
152
|
+
this.updateTimer = null;
|
|
144
153
|
|
|
145
154
|
const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);
|
|
146
155
|
|