@loaders.gl/loader-utils 4.2.0-alpha.3 → 4.2.0-alpha.5

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.
Files changed (144) hide show
  1. package/dist/index.cjs +66 -84
  2. package/dist/index.cjs.map +7 -0
  3. package/dist/index.d.ts +46 -46
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +18 -1
  6. package/dist/json-loader.d.ts +1 -1
  7. package/dist/json-loader.d.ts.map +1 -1
  8. package/dist/json-loader.js +20 -14
  9. package/dist/lib/binary-utils/array-buffer-utils.js +75 -46
  10. package/dist/lib/binary-utils/dataview-copy-utils.d.ts +1 -1
  11. package/dist/lib/binary-utils/dataview-copy-utils.d.ts.map +1 -1
  12. package/dist/lib/binary-utils/dataview-copy-utils.js +75 -34
  13. package/dist/lib/binary-utils/get-first-characters.js +39 -21
  14. package/dist/lib/binary-utils/memory-conversion-utils.js +38 -23
  15. package/dist/lib/binary-utils/memory-copy-utils.js +49 -20
  16. package/dist/lib/env-utils/assert.js +7 -4
  17. package/dist/lib/env-utils/globals.js +15 -7
  18. package/dist/lib/file-provider/data-view-file.d.ts +1 -1
  19. package/dist/lib/file-provider/data-view-file.d.ts.map +1 -1
  20. package/dist/lib/file-provider/data-view-file.js +58 -29
  21. package/dist/lib/file-provider/file-handle-file.d.ts +1 -1
  22. package/dist/lib/file-provider/file-handle-file.d.ts.map +1 -1
  23. package/dist/lib/file-provider/file-handle-file.js +96 -58
  24. package/dist/lib/file-provider/file-provider.js +8 -3
  25. package/dist/lib/files/blob-file.d.ts +1 -1
  26. package/dist/lib/files/blob-file.d.ts.map +1 -1
  27. package/dist/lib/files/blob-file.js +24 -23
  28. package/dist/lib/files/file.js +3 -1
  29. package/dist/lib/files/http-file.d.ts +1 -1
  30. package/dist/lib/files/http-file.d.ts.map +1 -1
  31. package/dist/lib/files/http-file.js +91 -71
  32. package/dist/lib/files/node-file-facade.d.ts +1 -1
  33. package/dist/lib/files/node-file-facade.d.ts.map +1 -1
  34. package/dist/lib/files/node-file-facade.js +37 -29
  35. package/dist/lib/files/sources.js +150 -1
  36. package/dist/lib/filesystems/filesystem.d.ts +1 -1
  37. package/dist/lib/filesystems/filesystem.d.ts.map +1 -1
  38. package/dist/lib/filesystems/filesystem.js +3 -1
  39. package/dist/lib/filesystems/node-filesystem-facade.d.ts +3 -3
  40. package/dist/lib/filesystems/node-filesystem-facade.d.ts.map +1 -1
  41. package/dist/lib/filesystems/node-filesystem-facade.js +41 -31
  42. package/dist/lib/iterators/async-iteration.js +39 -24
  43. package/dist/lib/iterators/text-iterators.js +46 -39
  44. package/dist/lib/node/buffer.browser.js +15 -3
  45. package/dist/lib/node/buffer.js +30 -16
  46. package/dist/lib/node/fs.browser.js +0 -1
  47. package/dist/lib/node/promisify.js +10 -4
  48. package/dist/lib/node/stream.browser.js +0 -1
  49. package/dist/lib/node/stream.js +4 -1
  50. package/dist/lib/option-utils/merge-loader-options.d.ts +1 -1
  51. package/dist/lib/option-utils/merge-loader-options.d.ts.map +1 -1
  52. package/dist/lib/option-utils/merge-loader-options.js +25 -17
  53. package/dist/lib/parser-utils/parse-json.js +9 -6
  54. package/dist/lib/path-utils/file-aliases.js +29 -13
  55. package/dist/lib/path-utils/get-cwd.js +6 -7
  56. package/dist/lib/path-utils/path.js +149 -105
  57. package/dist/lib/request-utils/request-scheduler.d.ts +2 -1
  58. package/dist/lib/request-utils/request-scheduler.d.ts.map +1 -1
  59. package/dist/lib/request-utils/request-scheduler.js +130 -102
  60. package/dist/lib/sources/data-source.js +48 -38
  61. package/dist/lib/sources/image-source.d.ts +3 -3
  62. package/dist/lib/sources/image-source.d.ts.map +1 -1
  63. package/dist/lib/sources/image-source.js +11 -3
  64. package/dist/lib/sources/image-tile-source.d.ts +3 -3
  65. package/dist/lib/sources/image-tile-source.d.ts.map +1 -1
  66. package/dist/lib/sources/image-tile-source.js +3 -1
  67. package/dist/lib/sources/tile-source-adapter.d.ts +2 -2
  68. package/dist/lib/sources/tile-source-adapter.d.ts.map +1 -1
  69. package/dist/lib/sources/tile-source-adapter.js +43 -36
  70. package/dist/lib/sources/tile-source.js +3 -1
  71. package/dist/lib/sources/utils/image-type.js +0 -1
  72. package/dist/lib/sources/utils/utils.js +31 -17
  73. package/dist/lib/sources/vector-tile-source.d.ts +2 -2
  74. package/dist/lib/sources/vector-tile-source.d.ts.map +1 -1
  75. package/dist/lib/sources/vector-tile-source.js +3 -1
  76. package/dist/lib/worker-loader-utils/create-loader-worker.d.ts +1 -1
  77. package/dist/lib/worker-loader-utils/create-loader-worker.d.ts.map +1 -1
  78. package/dist/lib/worker-loader-utils/create-loader-worker.js +87 -87
  79. package/dist/lib/worker-loader-utils/encode-with-worker.d.ts +1 -1
  80. package/dist/lib/worker-loader-utils/encode-with-worker.d.ts.map +1 -1
  81. package/dist/lib/worker-loader-utils/encode-with-worker.js +13 -8
  82. package/dist/lib/worker-loader-utils/parse-with-worker.d.ts +1 -1
  83. package/dist/lib/worker-loader-utils/parse-with-worker.d.ts.map +1 -1
  84. package/dist/lib/worker-loader-utils/parse-with-worker.js +68 -55
  85. package/dist/loader-types.d.ts +2 -2
  86. package/dist/loader-types.d.ts.map +1 -1
  87. package/dist/loader-types.js +26 -10
  88. package/dist/service-types.d.ts +1 -1
  89. package/dist/service-types.d.ts.map +1 -1
  90. package/dist/service-types.js +3 -1
  91. package/dist/types.js +1 -1
  92. package/dist/workers/json-worker.js +0 -1
  93. package/dist/writer-types.js +3 -1
  94. package/package.json +6 -4
  95. package/src/lib/request-utils/request-scheduler.ts +17 -8
  96. package/dist/index.js.map +0 -1
  97. package/dist/json-loader.js.map +0 -1
  98. package/dist/lib/binary-utils/array-buffer-utils.js.map +0 -1
  99. package/dist/lib/binary-utils/dataview-copy-utils.js.map +0 -1
  100. package/dist/lib/binary-utils/get-first-characters.js.map +0 -1
  101. package/dist/lib/binary-utils/memory-conversion-utils.js.map +0 -1
  102. package/dist/lib/binary-utils/memory-copy-utils.js.map +0 -1
  103. package/dist/lib/env-utils/assert.js.map +0 -1
  104. package/dist/lib/env-utils/globals.js.map +0 -1
  105. package/dist/lib/file-provider/data-view-file.js.map +0 -1
  106. package/dist/lib/file-provider/file-handle-file.js.map +0 -1
  107. package/dist/lib/file-provider/file-provider.js.map +0 -1
  108. package/dist/lib/files/blob-file.js.map +0 -1
  109. package/dist/lib/files/file.js.map +0 -1
  110. package/dist/lib/files/http-file.js.map +0 -1
  111. package/dist/lib/files/node-file-facade.js.map +0 -1
  112. package/dist/lib/files/sources.js.map +0 -1
  113. package/dist/lib/filesystems/filesystem.js.map +0 -1
  114. package/dist/lib/filesystems/node-filesystem-facade.js.map +0 -1
  115. package/dist/lib/iterators/async-iteration.js.map +0 -1
  116. package/dist/lib/iterators/text-iterators.js.map +0 -1
  117. package/dist/lib/node/buffer.browser.js.map +0 -1
  118. package/dist/lib/node/buffer.js.map +0 -1
  119. package/dist/lib/node/fs.browser.js.map +0 -1
  120. package/dist/lib/node/promisify.js.map +0 -1
  121. package/dist/lib/node/stream.browser.js.map +0 -1
  122. package/dist/lib/node/stream.js.map +0 -1
  123. package/dist/lib/option-utils/merge-loader-options.js.map +0 -1
  124. package/dist/lib/parser-utils/parse-json.js.map +0 -1
  125. package/dist/lib/path-utils/file-aliases.js.map +0 -1
  126. package/dist/lib/path-utils/get-cwd.js.map +0 -1
  127. package/dist/lib/path-utils/path.js.map +0 -1
  128. package/dist/lib/request-utils/request-scheduler.js.map +0 -1
  129. package/dist/lib/sources/data-source.js.map +0 -1
  130. package/dist/lib/sources/image-source.js.map +0 -1
  131. package/dist/lib/sources/image-tile-source.js.map +0 -1
  132. package/dist/lib/sources/tile-source-adapter.js.map +0 -1
  133. package/dist/lib/sources/tile-source.js.map +0 -1
  134. package/dist/lib/sources/utils/image-type.js.map +0 -1
  135. package/dist/lib/sources/utils/utils.js.map +0 -1
  136. package/dist/lib/sources/vector-tile-source.js.map +0 -1
  137. package/dist/lib/worker-loader-utils/create-loader-worker.js.map +0 -1
  138. package/dist/lib/worker-loader-utils/encode-with-worker.js.map +0 -1
  139. package/dist/lib/worker-loader-utils/parse-with-worker.js.map +0 -1
  140. package/dist/loader-types.js.map +0 -1
  141. package/dist/service-types.js.map +0 -1
  142. package/dist/types.js.map +0 -1
  143. package/dist/workers/json-worker.js.map +0 -1
  144. package/dist/writer-types.js.map +0 -1
@@ -1,24 +1,40 @@
1
+ // Simple file alias mechanisms for tests.
1
2
  let pathPrefix = '';
2
3
  const fileAliases = {};
4
+ /*
5
+ * Set a relative path prefix
6
+ */
3
7
  export function setPathPrefix(prefix) {
4
- pathPrefix = prefix;
8
+ pathPrefix = prefix;
5
9
  }
10
+ /*
11
+ * Get the relative path prefix
12
+ */
6
13
  export function getPathPrefix() {
7
- return pathPrefix;
14
+ return pathPrefix;
8
15
  }
16
+ /**
17
+ *
18
+ * @param aliases
19
+ *
20
+ * Note: addAliases are an experimental export, they are only for testing of loaders.gl loaders
21
+ * not intended as a generic aliasing mechanism
22
+ */
9
23
  export function addAliases(aliases) {
10
- Object.assign(fileAliases, aliases);
24
+ Object.assign(fileAliases, aliases);
11
25
  }
26
+ /**
27
+ * Resolves aliases and adds path-prefix to paths
28
+ */
12
29
  export function resolvePath(filename) {
13
- for (const alias in fileAliases) {
14
- if (filename.startsWith(alias)) {
15
- const replacement = fileAliases[alias];
16
- filename = filename.replace(alias, replacement);
30
+ for (const alias in fileAliases) {
31
+ if (filename.startsWith(alias)) {
32
+ const replacement = fileAliases[alias];
33
+ filename = filename.replace(alias, replacement);
34
+ }
17
35
  }
18
- }
19
- if (!filename.startsWith('http://') && !filename.startsWith('https://')) {
20
- filename = `${pathPrefix}${filename}`;
21
- }
22
- return filename;
36
+ if (!filename.startsWith('http://') && !filename.startsWith('https://')) {
37
+ filename = `${pathPrefix}${filename}`;
38
+ }
39
+ return filename;
23
40
  }
24
- //# sourceMappingURL=file-aliases.js.map
@@ -1,9 +1,8 @@
1
+ // loaders.gl MIT license
1
2
  export function getCWD() {
2
- var _window$location;
3
- if (typeof process !== 'undefined' && typeof process.cwd !== 'undefined') {
4
- return process.cwd();
5
- }
6
- const pathname = (_window$location = window.location) === null || _window$location === void 0 ? void 0 : _window$location.pathname;
7
- return (pathname === null || pathname === void 0 ? void 0 : pathname.slice(0, pathname.lastIndexOf('/') + 1)) || '';
3
+ if (typeof process !== 'undefined' && typeof process.cwd !== 'undefined') {
4
+ return process.cwd();
5
+ }
6
+ const pathname = window.location?.pathname;
7
+ return pathname?.slice(0, pathname.lastIndexOf('/') + 1) || '';
8
8
  }
9
- //# sourceMappingURL=get-cwd.js.map
@@ -1,127 +1,171 @@
1
+ // Beginning of a minimal implementation of the Node.js path API, that doesn't pull in big polyfills.
1
2
  import { getCWD } from "./get-cwd.js";
3
+ /**
4
+ * Replacement for Node.js path.filename
5
+ * @param url
6
+ */
2
7
  export function filename(url) {
3
- const slashIndex = url ? url.lastIndexOf('/') : -1;
4
- return slashIndex >= 0 ? url.substr(slashIndex + 1) : '';
8
+ const slashIndex = url ? url.lastIndexOf('/') : -1;
9
+ return slashIndex >= 0 ? url.substr(slashIndex + 1) : '';
5
10
  }
11
+ /**
12
+ * Replacement for Node.js path.dirname
13
+ * @param url
14
+ */
6
15
  export function dirname(url) {
7
- const slashIndex = url ? url.lastIndexOf('/') : -1;
8
- return slashIndex >= 0 ? url.substr(0, slashIndex) : '';
16
+ const slashIndex = url ? url.lastIndexOf('/') : -1;
17
+ return slashIndex >= 0 ? url.substr(0, slashIndex) : '';
9
18
  }
10
- export function join() {
11
- for (var _len = arguments.length, parts = new Array(_len), _key = 0; _key < _len; _key++) {
12
- parts[_key] = arguments[_key];
13
- }
14
- const separator = '/';
15
- parts = parts.map((part, index) => {
16
- if (index) {
17
- part = part.replace(new RegExp(`^${separator}`), '');
19
+ /**
20
+ * Replacement for Node.js path.join
21
+ * @param parts
22
+ */
23
+ export function join(...parts) {
24
+ const separator = '/';
25
+ parts = parts.map((part, index) => {
26
+ if (index) {
27
+ part = part.replace(new RegExp(`^${separator}`), '');
28
+ }
29
+ if (index !== parts.length - 1) {
30
+ part = part.replace(new RegExp(`${separator}$`), '');
31
+ }
32
+ return part;
33
+ });
34
+ return parts.join(separator);
35
+ }
36
+ /* eslint-disable no-continue */
37
+ /**
38
+ * https://nodejs.org/api/path.html#path_path_resolve_paths
39
+ * @param paths A sequence of paths or path segments.
40
+ * @return resolved path
41
+ * Forked from BTOdell/path-resolve under MIT license
42
+ * @see https://github.com/BTOdell/path-resolve/blob/master/LICENSE
43
+ */
44
+ export function resolve(...components) {
45
+ const paths = [];
46
+ for (let _i = 0; _i < components.length; _i++) {
47
+ paths[_i] = components[_i];
18
48
  }
19
- if (index !== parts.length - 1) {
20
- part = part.replace(new RegExp(`${separator}$`), '');
49
+ let resolvedPath = '';
50
+ let resolvedAbsolute = false;
51
+ let cwd;
52
+ for (let i = paths.length - 1; i >= -1 && !resolvedAbsolute; i--) {
53
+ let path;
54
+ if (i >= 0) {
55
+ path = paths[i];
56
+ }
57
+ else {
58
+ if (cwd === undefined) {
59
+ cwd = getCWD();
60
+ }
61
+ path = cwd;
62
+ }
63
+ // Skip empty entries
64
+ if (path.length === 0) {
65
+ continue;
66
+ }
67
+ resolvedPath = `${path}/${resolvedPath}`;
68
+ resolvedAbsolute = path.charCodeAt(0) === SLASH;
21
69
  }
22
- return part;
23
- });
24
- return parts.join(separator);
25
- }
26
- export function resolve() {
27
- const paths = [];
28
- for (let _i = 0; _i < arguments.length; _i++) {
29
- paths[_i] = _i < 0 || arguments.length <= _i ? undefined : arguments[_i];
30
- }
31
- let resolvedPath = '';
32
- let resolvedAbsolute = false;
33
- let cwd;
34
- for (let i = paths.length - 1; i >= -1 && !resolvedAbsolute; i--) {
35
- let path;
36
- if (i >= 0) {
37
- path = paths[i];
38
- } else {
39
- if (cwd === undefined) {
40
- cwd = getCWD();
41
- }
42
- path = cwd;
70
+ // At this point the path should be resolved to a full absolute path, but
71
+ // handle relative paths to be safe (might happen when process.cwd() fails)
72
+ // Normalize the path (removes leading slash)
73
+ resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
74
+ if (resolvedAbsolute) {
75
+ return `/${resolvedPath}`;
43
76
  }
44
- if (path.length === 0) {
45
- continue;
77
+ else if (resolvedPath.length > 0) {
78
+ return resolvedPath;
46
79
  }
47
- resolvedPath = `${path}/${resolvedPath}`;
48
- resolvedAbsolute = path.charCodeAt(0) === SLASH;
49
- }
50
- resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
51
- if (resolvedAbsolute) {
52
- return `/${resolvedPath}`;
53
- } else if (resolvedPath.length > 0) {
54
- return resolvedPath;
55
- }
56
- return '.';
80
+ return '.';
57
81
  }
58
82
  const SLASH = 47;
59
83
  const DOT = 46;
84
+ /**
85
+ * Resolves . and .. elements in a path with directory names
86
+ * Forked from BTOdell/path-resolve under MIT license
87
+ * @see https://github.com/BTOdell/path-resolve/blob/master/LICENSE
88
+ */
89
+ /* eslint-disable max-depth */
90
+ // eslint-disable-next-line complexity, max-statements
60
91
  function normalizeStringPosix(path, allowAboveRoot) {
61
- let res = '';
62
- let lastSlash = -1;
63
- let dots = 0;
64
- let code;
65
- let isAboveRoot = false;
66
- for (let i = 0; i <= path.length; ++i) {
67
- if (i < path.length) {
68
- code = path.charCodeAt(i);
69
- } else if (code === SLASH) {
70
- break;
71
- } else {
72
- code = SLASH;
73
- }
74
- if (code === SLASH) {
75
- if (lastSlash === i - 1 || dots === 1) {} else if (lastSlash !== i - 1 && dots === 2) {
76
- if (res.length < 2 || !isAboveRoot || res.charCodeAt(res.length - 1) !== DOT || res.charCodeAt(res.length - 2) !== DOT) {
77
- if (res.length > 2) {
78
- const start = res.length - 1;
79
- let j = start;
80
- for (; j >= 0; --j) {
81
- if (res.charCodeAt(j) === SLASH) {
82
- break;
83
- }
92
+ let res = '';
93
+ let lastSlash = -1;
94
+ let dots = 0;
95
+ let code;
96
+ let isAboveRoot = false;
97
+ for (let i = 0; i <= path.length; ++i) {
98
+ if (i < path.length) {
99
+ code = path.charCodeAt(i);
100
+ }
101
+ else if (code === SLASH) {
102
+ break;
103
+ }
104
+ else {
105
+ code = SLASH;
106
+ }
107
+ if (code === SLASH) {
108
+ if (lastSlash === i - 1 || dots === 1) {
109
+ // NOOP
110
+ }
111
+ else if (lastSlash !== i - 1 && dots === 2) {
112
+ if (res.length < 2 ||
113
+ !isAboveRoot ||
114
+ res.charCodeAt(res.length - 1) !== DOT ||
115
+ res.charCodeAt(res.length - 2) !== DOT) {
116
+ if (res.length > 2) {
117
+ const start = res.length - 1;
118
+ let j = start;
119
+ for (; j >= 0; --j) {
120
+ if (res.charCodeAt(j) === SLASH) {
121
+ break;
122
+ }
123
+ }
124
+ if (j !== start) {
125
+ res = j === -1 ? '' : res.slice(0, j);
126
+ lastSlash = i;
127
+ dots = 0;
128
+ isAboveRoot = false;
129
+ continue;
130
+ }
131
+ }
132
+ else if (res.length === 2 || res.length === 1) {
133
+ res = '';
134
+ lastSlash = i;
135
+ dots = 0;
136
+ isAboveRoot = false;
137
+ continue;
138
+ }
139
+ }
140
+ if (allowAboveRoot) {
141
+ if (res.length > 0) {
142
+ res += '/..';
143
+ }
144
+ else {
145
+ res = '..';
146
+ }
147
+ isAboveRoot = true;
148
+ }
84
149
  }
85
- if (j !== start) {
86
- res = j === -1 ? '' : res.slice(0, j);
87
- lastSlash = i;
88
- dots = 0;
89
- isAboveRoot = false;
90
- continue;
150
+ else {
151
+ const slice = path.slice(lastSlash + 1, i);
152
+ if (res.length > 0) {
153
+ res += `/${slice}`;
154
+ }
155
+ else {
156
+ res = slice;
157
+ }
158
+ isAboveRoot = false;
91
159
  }
92
- } else if (res.length === 2 || res.length === 1) {
93
- res = '';
94
160
  lastSlash = i;
95
161
  dots = 0;
96
- isAboveRoot = false;
97
- continue;
98
- }
99
162
  }
100
- if (allowAboveRoot) {
101
- if (res.length > 0) {
102
- res += '/..';
103
- } else {
104
- res = '..';
105
- }
106
- isAboveRoot = true;
163
+ else if (code === DOT && dots !== -1) {
164
+ ++dots;
107
165
  }
108
- } else {
109
- const slice = path.slice(lastSlash + 1, i);
110
- if (res.length > 0) {
111
- res += `/${slice}`;
112
- } else {
113
- res = slice;
166
+ else {
167
+ dots = -1;
114
168
  }
115
- isAboveRoot = false;
116
- }
117
- lastSlash = i;
118
- dots = 0;
119
- } else if (code === DOT && dots !== -1) {
120
- ++dots;
121
- } else {
122
- dots = -1;
123
169
  }
124
- }
125
- return res;
170
+ return res;
126
171
  }
127
- //# sourceMappingURL=path.js.map
@@ -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"}
@@ -5,115 +5,143 @@ const STAT_CANCELLED_REQUESTS = 'Cancelled Requests';
5
5
  const STAT_QUEUED_REQUESTS_EVER = 'Queued Requests Ever';
6
6
  const STAT_ACTIVE_REQUESTS_EVER = 'Active Requests Ever';
7
7
  const DEFAULT_PROPS = {
8
- id: 'request-scheduler',
9
- throttleRequests: true,
10
- maxRequests: 6
8
+ id: 'request-scheduler',
9
+ /** Specifies if the request scheduler should throttle incoming requests, mainly for comparative testing. */
10
+ throttleRequests: true,
11
+ /** The maximum number of simultaneous active requests. Un-throttled requests do not observe this limit. */
12
+ maxRequests: 6,
13
+ /**
14
+ * Specifies a debounce time, in milliseconds. All requests are queued, until no new requests have
15
+ * been added to the queue for this amount of time.
16
+ */
17
+ debounceTime: 0
11
18
  };
19
+ /**
20
+ * Used to issue a request, without having them "deeply queued" by the browser.
21
+ * @todo - Track requests globally, across multiple servers
22
+ */
12
23
  export default class RequestScheduler {
13
- constructor() {
14
- let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
15
- this.props = void 0;
16
- this.stats = void 0;
17
- this.activeRequestCount = 0;
18
- this.requestQueue = [];
19
- this.requestMap = new Map();
20
- this.deferredUpdate = null;
21
- this.props = {
22
- ...DEFAULT_PROPS,
23
- ...props
24
- };
25
- this.stats = new Stats({
26
- id: this.props.id
27
- });
28
- this.stats.get(STAT_QUEUED_REQUESTS);
29
- this.stats.get(STAT_ACTIVE_REQUESTS);
30
- this.stats.get(STAT_CANCELLED_REQUESTS);
31
- this.stats.get(STAT_QUEUED_REQUESTS_EVER);
32
- this.stats.get(STAT_ACTIVE_REQUESTS_EVER);
33
- }
34
- scheduleRequest(handle) {
35
- let getPriority = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : () => 0;
36
- if (!this.props.throttleRequests) {
37
- return Promise.resolve({
38
- done: () => {}
39
- });
24
+ constructor(props = {}) {
25
+ this.activeRequestCount = 0;
26
+ /** Tracks the number of active requests and prioritizes/cancels queued requests. */
27
+ this.requestQueue = [];
28
+ this.requestMap = new Map();
29
+ this.updateTimer = null;
30
+ this.props = { ...DEFAULT_PROPS, ...props };
31
+ // Returns the statistics used by the request scheduler.
32
+ this.stats = new Stats({ id: this.props.id });
33
+ this.stats.get(STAT_QUEUED_REQUESTS);
34
+ this.stats.get(STAT_ACTIVE_REQUESTS);
35
+ this.stats.get(STAT_CANCELLED_REQUESTS);
36
+ this.stats.get(STAT_QUEUED_REQUESTS_EVER);
37
+ this.stats.get(STAT_ACTIVE_REQUESTS_EVER);
40
38
  }
41
- if (this.requestMap.has(handle)) {
42
- return this.requestMap.get(handle);
43
- }
44
- const request = {
45
- handle,
46
- priority: 0,
47
- getPriority
48
- };
49
- const promise = new Promise(resolve => {
50
- request.resolve = resolve;
51
- return request;
52
- });
53
- this.requestQueue.push(request);
54
- this.requestMap.set(handle, promise);
55
- this._issueNewRequests();
56
- return promise;
57
- }
58
- _issueRequest(request) {
59
- const {
60
- handle,
61
- resolve
62
- } = request;
63
- let isDone = false;
64
- const done = () => {
65
- if (!isDone) {
66
- isDone = true;
67
- this.requestMap.delete(handle);
68
- this.activeRequestCount--;
39
+ /**
40
+ * Called by an application that wants to issue a request, without having it deeply queued by the browser
41
+ *
42
+ * When the returned promise resolved, it is OK for the application to issue a request.
43
+ * The promise resolves to an object that contains a `done` method.
44
+ * When the application's request has completed (or failed), the application must call the `done` function
45
+ *
46
+ * @param handle
47
+ * @param getPriority will be called when request "slots" open up,
48
+ * allowing the caller to update priority or cancel the request
49
+ * Highest priority executes first, priority < 0 cancels the request
50
+ * @returns a promise
51
+ * - resolves to a object (with a `done` field) when the request can be issued without queueing,
52
+ * - resolves to `null` if the request has been cancelled (by the callback return < 0).
53
+ * In this case the application should not issue the request
54
+ */
55
+ scheduleRequest(handle, getPriority = () => 0) {
56
+ // Allows throttling to be disabled
57
+ if (!this.props.throttleRequests) {
58
+ return Promise.resolve({ done: () => { } });
59
+ }
60
+ // dedupe
61
+ if (this.requestMap.has(handle)) {
62
+ return this.requestMap.get(handle);
63
+ }
64
+ const request = { handle, priority: 0, getPriority };
65
+ const promise = new Promise((resolve) => {
66
+ // @ts-ignore
67
+ request.resolve = resolve;
68
+ return request;
69
+ });
70
+ this.requestQueue.push(request);
71
+ this.requestMap.set(handle, promise);
69
72
  this._issueNewRequests();
70
- }
71
- };
72
- this.activeRequestCount++;
73
- return resolve ? resolve({
74
- done
75
- }) : Promise.resolve({
76
- done
77
- });
78
- }
79
- _issueNewRequests() {
80
- if (!this.deferredUpdate) {
81
- this.deferredUpdate = setTimeout(() => this._issueNewRequestsAsync(), 0);
73
+ return promise;
74
+ }
75
+ // PRIVATE
76
+ _issueRequest(request) {
77
+ const { handle, resolve } = request;
78
+ let isDone = false;
79
+ const done = () => {
80
+ // can only be called once
81
+ if (!isDone) {
82
+ isDone = true;
83
+ // Stop tracking a request - it has completed, failed, cancelled etc
84
+ this.requestMap.delete(handle);
85
+ this.activeRequestCount--;
86
+ // A slot just freed up, see if any queued requests are waiting
87
+ this._issueNewRequests();
88
+ }
89
+ };
90
+ // Track this request
91
+ this.activeRequestCount++;
92
+ return resolve ? resolve({ done }) : Promise.resolve({ done });
82
93
  }
83
- }
84
- _issueNewRequestsAsync() {
85
- this.deferredUpdate = null;
86
- const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);
87
- if (freeSlots === 0) {
88
- return;
94
+ /** We check requests asynchronously, to prevent multiple updates */
95
+ _issueNewRequests() {
96
+ if (this.updateTimer !== null) {
97
+ clearTimeout(this.updateTimer);
98
+ }
99
+ this.updateTimer = setTimeout(() => this._issueNewRequestsAsync(), this.props.debounceTime);
89
100
  }
90
- this._updateAllRequests();
91
- for (let i = 0; i < freeSlots; ++i) {
92
- const request = this.requestQueue.shift();
93
- if (request) {
94
- this._issueRequest(request);
95
- }
101
+ /** Refresh all requests */
102
+ _issueNewRequestsAsync() {
103
+ if (this.updateTimer !== null) {
104
+ clearTimeout(this.updateTimer);
105
+ }
106
+ this.updateTimer = null;
107
+ const freeSlots = Math.max(this.props.maxRequests - this.activeRequestCount, 0);
108
+ if (freeSlots === 0) {
109
+ return;
110
+ }
111
+ this._updateAllRequests();
112
+ // Resolve pending promises for the top-priority requests
113
+ for (let i = 0; i < freeSlots; ++i) {
114
+ const request = this.requestQueue.shift();
115
+ if (request) {
116
+ this._issueRequest(request); // eslint-disable-line @typescript-eslint/no-floating-promises
117
+ }
118
+ }
119
+ // Uncomment to debug
120
+ // console.log(`${freeSlots} free slots, ${this.requestQueue.length} queued requests`);
96
121
  }
97
- }
98
- _updateAllRequests() {
99
- const requestQueue = this.requestQueue;
100
- for (let i = 0; i < requestQueue.length; ++i) {
101
- const request = requestQueue[i];
102
- if (!this._updateRequest(request)) {
103
- requestQueue.splice(i, 1);
104
- this.requestMap.delete(request.handle);
105
- i--;
106
- }
122
+ /** Ensure all requests have updated priorities, and that no longer valid requests are cancelled */
123
+ _updateAllRequests() {
124
+ const requestQueue = this.requestQueue;
125
+ for (let i = 0; i < requestQueue.length; ++i) {
126
+ const request = requestQueue[i];
127
+ if (!this._updateRequest(request)) {
128
+ // Remove the element and make sure to adjust the counter to account for shortened array
129
+ requestQueue.splice(i, 1);
130
+ this.requestMap.delete(request.handle);
131
+ i--;
132
+ }
133
+ }
134
+ // Sort the remaining requests based on priority
135
+ requestQueue.sort((a, b) => a.priority - b.priority);
107
136
  }
108
- requestQueue.sort((a, b) => a.priority - b.priority);
109
- }
110
- _updateRequest(request) {
111
- request.priority = request.getPriority(request.handle);
112
- if (request.priority < 0) {
113
- request.resolve(null);
114
- return false;
137
+ /** Update a single request by calling the callback */
138
+ _updateRequest(request) {
139
+ request.priority = request.getPriority(request.handle); // eslint-disable-line callback-return
140
+ // by returning a negative priority, the callback cancels the request
141
+ if (request.priority < 0) {
142
+ request.resolve(null);
143
+ return false;
144
+ }
145
+ return true;
115
146
  }
116
- return true;
117
- }
118
147
  }
119
- //# sourceMappingURL=request-scheduler.js.map