Skip to content

Commit 3526ca0

Browse files
authored
Merge pull request #1310 from mathjax/update/loader
Better support for Loader.preLoaded() when used in combined components in node
2 parents 910e2ed + 0e44b99 commit 3526ca0

File tree

2 files changed

+81
-28
lines changed

2 files changed

+81
-28
lines changed

ts/components/loader.ts

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ export const Loader = {
169169
*/
170170
versions: new Map<string, string>(),
171171

172+
/**
173+
* Array of nested load promises so if component performs additional
174+
* loads (like an output jax with an alternate font), then the
175+
* outer load promises won't resolve until the inner ones are complete.
176+
*/
177+
nestedLoads: [] as Promise<any[]>[],
178+
172179
/**
173180
* Get a promise that is resolved when all the named packages have been loaded.
174181
*
@@ -191,37 +198,83 @@ export const Loader = {
191198
* Load the named packages and return a promise that is resolved when they are all loaded
192199
*
193200
* @param {string[]} names The packages to load
194-
* @returns {Promise} A promise that resolves when all the named packages are ready
201+
* @returns {Promise<any[]>} A promise that resolves when all the named packages are ready
195202
*/
196203
load(...names: string[]): Promise<any[]> {
197204
if (names.length === 0) {
198205
return Promise.resolve([]);
199206
}
200-
const promises = [];
201-
for (const name of names) {
202-
let extension = Package.packages.get(name);
203-
if (!extension) {
204-
extension = new Package(name);
205-
extension.provides(CONFIG.provides[name]);
207+
//
208+
// Add a new array to store promises for this load() call
209+
//
210+
let nested = [] as Promise<any>[];
211+
this.nestedLoads.unshift(nested);
212+
//
213+
// Create a promise for this load() call
214+
//
215+
const promise = Promise.resolve().then(async () => {
216+
//
217+
// Collect the promises for all the named packages,
218+
// creating the package if needed, and add checks
219+
// for the version numbers used in the components.
220+
//
221+
const promises = [];
222+
for (const name of names) {
223+
let extension = Package.packages.get(name);
224+
if (!extension) {
225+
extension = new Package(name);
226+
extension.provides(CONFIG.provides[name]);
227+
}
228+
extension.checkNoLoad();
229+
promises.push(
230+
extension.promise.then(() => {
231+
if (
232+
CONFIG.versionWarnings &&
233+
extension.isLoaded &&
234+
!Loader.versions.has(Package.resolvePath(name))
235+
) {
236+
console.warn(
237+
`No version information available for component ${name}`
238+
);
239+
}
240+
return extension.result;
241+
}) as Promise<any>
242+
);
206243
}
207-
extension.checkNoLoad();
208-
promises.push(
209-
extension.promise.then(() => {
210-
if (
211-
CONFIG.versionWarnings &&
212-
extension.isLoaded &&
213-
!Loader.versions.has(Package.resolvePath(name))
214-
) {
215-
console.warn(
216-
`No version information available for component ${name}`
217-
);
218-
}
219-
return extension.result;
220-
}) as Promise<any>
221-
);
222-
}
223-
Package.loadAll();
224-
return Promise.all(promises);
244+
//
245+
// Load everything that was requested and wait for
246+
// them to be loaded.
247+
//
248+
Package.loadAll();
249+
const result = await Promise.all(promises);
250+
//
251+
// If any other loads occurred while we were waiting,
252+
// Wait for those promises, and clear the list so that
253+
// if even MORE loads occur while waiting for those,
254+
// we can wait for them, too. Keep doing that until
255+
// no additional loads occurred, in which case we are
256+
// now done.
257+
//
258+
while (nested.length) {
259+
const promise = Promise.all(nested);
260+
nested = this.nestedLoads[this.nestedLoads.indexOf(nested)] = [];
261+
await promise;
262+
}
263+
//
264+
// Remove the (empty) list from the nested list,
265+
// and return the result.
266+
//
267+
this.nestedLoads.splice(this.nestedLoads.indexOf(nested), 1);
268+
return result;
269+
});
270+
//
271+
// Add this load promise to the lists for any parent load() call that are
272+
// pending when this load() was performed, then return the load promise.
273+
//
274+
this.nestedLoads
275+
.slice(1)
276+
.forEach((list: Promise<any>[]) => list.push(promise));
277+
return promise;
225278
},
226279

227280
/**

ts/components/package.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ export class Package {
159159
*/
160160
public static loadPromise(name: string): Promise<void> {
161161
const config = (CONFIG[name] || {}) as PackageConfig;
162-
const promise = Promise.all(
163-
(config.extraLoads || []).map((name) => Loader.load(name))
164-
);
162+
const promise = config.extraLoads
163+
? Loader.load(...config.extraLoads)
164+
: Promise.resolve();
165165
const checkReady = config.checkReady || (() => Promise.resolve());
166166
return promise.then(() => checkReady()) as Promise<void>;
167167
}

0 commit comments

Comments
 (0)