@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 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
- // Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing
534
+ /** Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing. */
535
535
  throttleRequests: true,
536
- // The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit.
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.deferredUpdate = null;
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 (!this.deferredUpdate) {
606
- this.deferredUpdate = setTimeout(() => this._issueNewRequestsAsync(), 0);
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.deferredUpdate = null;
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;
@@ -1,4 +1,4 @@
1
- const VERSION = typeof "4.1.3" !== 'undefined' ? "4.1.3" : 'latest';
1
+ const VERSION = typeof "4.1.4" !== 'undefined' ? "4.1.4" : 'latest';
2
2
  export const JSONLoader = {
3
3
  name: 'JSON',
4
4
  id: 'json',
@@ -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 deferredUpdate;
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;CACtB,CAAC;AAgBF,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,cAAc,CAAa;gBAEvB,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;IAMzB,4BAA4B;IAC5B,sBAAsB;IAwBtB,mGAAmG;IACnG,kBAAkB;IAgBlB,sDAAsD;IACtD,cAAc,CAAC,OAAO,KAAA;CAUvB"}
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.deferredUpdate = null;
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 (!this.deferredUpdate) {
81
- this.deferredUpdate = setTimeout(() => this._issueNewRequestsAsync(), 0);
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.deferredUpdate = null;
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",
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.3",
50
+ "@loaders.gl/worker-utils": "4.1.4",
51
51
  "@probe.gl/stats": "^4.0.2"
52
52
  },
53
- "gitHead": "4313c1f68c25723ab3e906db5a6ac65c2e8ac7b6"
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
- // Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing
26
+ /** Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing. */
26
27
  throttleRequests: true,
27
- // The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit.
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 deferredUpdate: any = null;
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 (!this.deferredUpdate) {
136
- this.deferredUpdate = setTimeout(() => this._issueNewRequestsAsync(), 0);
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
- // TODO - shouldn't we clear the timeout?
143
- this.deferredUpdate = null;
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