Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/module/modulemanager.js
2868 views
1
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview A singleton object for managing Javascript code modules.
17
*
18
*/
19
20
goog.provide('goog.module.ModuleManager');
21
goog.provide('goog.module.ModuleManager.CallbackType');
22
goog.provide('goog.module.ModuleManager.FailureType');
23
24
goog.require('goog.Disposable');
25
goog.require('goog.array');
26
goog.require('goog.asserts');
27
goog.require('goog.async.Deferred');
28
goog.require('goog.debug.Trace');
29
/** @suppress {extraRequire} */
30
goog.require('goog.dispose');
31
goog.require('goog.log');
32
/** @suppress {extraRequire} */
33
goog.require('goog.module');
34
/** @suppress {extraRequire} interface */
35
goog.require('goog.module.AbstractModuleLoader');
36
goog.require('goog.module.ModuleInfo');
37
goog.require('goog.module.ModuleLoadCallback');
38
goog.require('goog.object');
39
40
41
42
/**
43
* The ModuleManager keeps track of all modules in the environment.
44
* Since modules may not have their code loaded, we must keep track of them.
45
* @constructor
46
* @extends {goog.Disposable}
47
* @struct
48
*/
49
goog.module.ModuleManager = function() {
50
goog.module.ModuleManager.base(this, 'constructor');
51
52
/**
53
* A mapping from module id to ModuleInfo object.
54
* @private {Object<string, !goog.module.ModuleInfo>}
55
*/
56
this.moduleInfoMap_ = {};
57
58
// TODO (malteubl): Switch this to a reentrant design.
59
/**
60
* The ids of the currently loading modules. If batch mode is disabled, then
61
* this array will never contain more than one element at a time.
62
* @type {Array<string>}
63
* @private
64
*/
65
this.loadingModuleIds_ = [];
66
67
/**
68
* The requested ids of the currently loading modules. This does not include
69
* module dependencies that may also be loading.
70
* @type {Array<string>}
71
* @private
72
*/
73
this.requestedLoadingModuleIds_ = [];
74
75
// TODO(user): Make these and other arrays that are used as sets be
76
// actual sets.
77
/**
78
* All module ids that have ever been requested. In concurrent loading these
79
* are the ones to subtract from future requests.
80
* @type {!Array<string>}
81
* @private
82
*/
83
this.requestedModuleIds_ = [];
84
85
/**
86
* A queue of the ids of requested but not-yet-loaded modules. The zero
87
* position is the front of the queue. This is a 2-D array to group modules
88
* together with other modules that should be batch loaded with them, if
89
* batch loading is enabled.
90
* @type {Array<Array<string>>}
91
* @private
92
*/
93
this.requestedModuleIdsQueue_ = [];
94
95
/**
96
* The ids of the currently loading modules which have been initiated by user
97
* actions.
98
* @type {Array<string>}
99
* @private
100
*/
101
this.userInitiatedLoadingModuleIds_ = [];
102
103
/**
104
* A map of callback types to the functions to call for the specified
105
* callback type.
106
* @type {Object<goog.module.ModuleManager.CallbackType, Array<Function>>}
107
* @private
108
*/
109
this.callbackMap_ = {};
110
111
/**
112
* Module info for the base module (the one that contains the module
113
* manager code), which we set as the loading module so one can
114
* register initialization callbacks in the base module.
115
*
116
* The base module is considered loaded when #setAllModuleInfo is called or
117
* #setModuleContext is called, whichever comes first.
118
*
119
* @type {goog.module.ModuleInfo}
120
* @private
121
*/
122
this.baseModuleInfo_ = new goog.module.ModuleInfo([], '');
123
124
/**
125
* The module that is currently loading, or null if not loading anything.
126
* @type {goog.module.ModuleInfo}
127
* @private
128
*/
129
this.currentlyLoadingModule_ = this.baseModuleInfo_;
130
131
/**
132
* The id of the last requested initial module. When it loaded
133
* the deferred in {@code this.initialModulesLoaded_} resolves.
134
* @private {?string}
135
*/
136
this.lastInitialModuleId_ = null;
137
138
/**
139
* Deferred for when all initial modules have loaded. We currently block
140
* sending additional module requests until this deferred resolves. In a
141
* future optimization it may be possible to use the initial modules as
142
* seeds for the module loader "requested module ids" and start making new
143
* requests even sooner.
144
* @private {!goog.async.Deferred}
145
*/
146
this.initialModulesLoaded_ = new goog.async.Deferred();
147
148
/**
149
* A logger.
150
* @private {goog.log.Logger}
151
*/
152
this.logger_ = goog.log.getLogger('goog.module.ModuleManager');
153
154
/**
155
* Whether the batch mode (i.e. the loading of multiple modules with just one
156
* request) has been enabled.
157
* @private {boolean}
158
*/
159
this.batchModeEnabled_ = false;
160
161
/**
162
* Whether the module requests may be sent out of order.
163
* @private {boolean}
164
*/
165
this.concurrentLoadingEnabled_ = false;
166
167
/**
168
* A loader for the modules that implements loadModules(ids, moduleInfoMap,
169
* opt_successFn, opt_errorFn, opt_timeoutFn, opt_forceReload) method.
170
* @private {goog.module.AbstractModuleLoader}
171
*/
172
this.loader_ = null;
173
174
// TODO(user): Remove tracer.
175
/**
176
* Tracer that measures how long it takes to load a module.
177
* @private {?number}
178
*/
179
this.loadTracer_ = null;
180
181
/**
182
* The number of consecutive failures that have happened upon module load
183
* requests.
184
* @private {number}
185
*/
186
this.consecutiveFailures_ = 0;
187
188
/**
189
* Determines if the module manager was just active before the processing of
190
* the last data.
191
* @private {boolean}
192
*/
193
this.lastActive_ = false;
194
195
/**
196
* Determines if the module manager was just user active before the processing
197
* of the last data. The module manager is user active if any of the
198
* user-initiated modules are loading or queued up to load.
199
* @private {boolean}
200
*/
201
this.userLastActive_ = false;
202
203
/**
204
* The module context needed for module initialization.
205
* @private {Object}
206
*/
207
this.moduleContext_ = null;
208
};
209
goog.inherits(goog.module.ModuleManager, goog.Disposable);
210
goog.addSingletonGetter(goog.module.ModuleManager);
211
212
213
/**
214
* The type of callbacks that can be registered with the module manager,.
215
* @enum {string}
216
*/
217
goog.module.ModuleManager.CallbackType = {
218
/**
219
* Fired when an error has occurred.
220
*/
221
ERROR: 'error',
222
223
/**
224
* Fired when it becomes idle and has no more module loads to process.
225
*/
226
IDLE: 'idle',
227
228
/**
229
* Fired when it becomes active and has module loads to process.
230
*/
231
ACTIVE: 'active',
232
233
/**
234
* Fired when it becomes idle and has no more user-initiated module loads to
235
* process.
236
*/
237
USER_IDLE: 'userIdle',
238
239
/**
240
* Fired when it becomes active and has user-initiated module loads to
241
* process.
242
*/
243
USER_ACTIVE: 'userActive'
244
};
245
246
247
/**
248
* A non-HTTP status code indicating a corruption in loaded module.
249
* This should be used by a ModuleLoader as a replacement for the HTTP code
250
* given to the error handler function to indicated that the module was
251
* corrupted.
252
* This will set the forceReload flag on the loadModules method when retrying
253
* module loading.
254
* @type {number}
255
*/
256
goog.module.ModuleManager.CORRUPT_RESPONSE_STATUS_CODE = 8001;
257
258
259
/**
260
* Sets the batch mode as enabled or disabled for the module manager.
261
* @param {boolean} enabled Whether the batch mode is to be enabled or not.
262
*/
263
goog.module.ModuleManager.prototype.setBatchModeEnabled = function(enabled) {
264
this.batchModeEnabled_ = enabled;
265
};
266
267
268
/**
269
* Sets the concurrent loading mode as enabled or disabled for the module
270
* manager. Requires a moduleloader implementation that supports concurrent
271
* loads. The default {@see goog.module.ModuleLoader} does not.
272
* @param {boolean} enabled
273
*/
274
goog.module.ModuleManager.prototype.setConcurrentLoadingEnabled = function(
275
enabled) {
276
this.concurrentLoadingEnabled_ = enabled;
277
};
278
279
280
/**
281
* Sets the module info for all modules. Should only be called once.
282
*
283
* @param {Object<Array<string>>} infoMap An object that contains a mapping
284
* from module id (String) to list of required module ids (Array).
285
*/
286
goog.module.ModuleManager.prototype.setAllModuleInfo = function(infoMap) {
287
for (var id in infoMap) {
288
this.moduleInfoMap_[id] = new goog.module.ModuleInfo(infoMap[id], id);
289
}
290
if (!this.initialModulesLoaded_.hasFired()) {
291
this.initialModulesLoaded_.callback();
292
}
293
this.maybeFinishBaseLoad_();
294
};
295
296
297
/**
298
* Sets the module info for all modules. Should only be called once. Also
299
* marks modules that are currently being loaded.
300
*
301
* @param {string=} opt_info A string representation of the module dependency
302
* graph, in the form: module1:dep1,dep2/module2:dep1,dep2 etc.
303
* Where depX is the base-36 encoded position of the dep in the module list.
304
* @param {Array<string>=} opt_loadingModuleIds A list of moduleIds that
305
* are currently being loaded.
306
*/
307
goog.module.ModuleManager.prototype.setAllModuleInfoString = function(
308
opt_info, opt_loadingModuleIds) {
309
if (!goog.isString(opt_info)) {
310
// The call to this method is generated in two steps, the argument is added
311
// after some of the compilation passes. This means that the initial code
312
// doesn't have any arguments and causes compiler errors. We make it
313
// optional to satisfy this constraint.
314
return;
315
}
316
317
var modules = opt_info.split('/');
318
var moduleIds = [];
319
320
// Split the string into the infoMap of id->deps
321
for (var i = 0; i < modules.length; i++) {
322
var parts = modules[i].split(':');
323
var id = parts[0];
324
var deps;
325
if (parts[1]) {
326
deps = parts[1].split(',');
327
for (var j = 0; j < deps.length; j++) {
328
var index = parseInt(deps[j], 36);
329
goog.asserts.assert(
330
moduleIds[index], 'No module @ %s, dep of %s @ %s', index, id, i);
331
deps[j] = moduleIds[index];
332
}
333
} else {
334
deps = [];
335
}
336
moduleIds.push(id);
337
this.moduleInfoMap_[id] = new goog.module.ModuleInfo(deps, id);
338
}
339
if (opt_loadingModuleIds && opt_loadingModuleIds.length) {
340
goog.array.extend(this.loadingModuleIds_, opt_loadingModuleIds);
341
// The last module in the list of initial modules. When it has loaded all
342
// initial modules have loaded.
343
this.lastInitialModuleId_ =
344
/** @type {?string} */ (goog.array.peek(opt_loadingModuleIds));
345
} else {
346
if (!this.initialModulesLoaded_.hasFired()) {
347
this.initialModulesLoaded_.callback();
348
}
349
}
350
this.maybeFinishBaseLoad_();
351
};
352
353
354
/**
355
* Gets a module info object by id.
356
* @param {string} id A module identifier.
357
* @return {!goog.module.ModuleInfo} The module info.
358
*/
359
goog.module.ModuleManager.prototype.getModuleInfo = function(id) {
360
return this.moduleInfoMap_[id];
361
};
362
363
364
/**
365
* Sets the module uris.
366
*
367
* @param {Object} moduleUriMap The map of id/uris pairs for each module.
368
*/
369
goog.module.ModuleManager.prototype.setModuleUris = function(moduleUriMap) {
370
for (var id in moduleUriMap) {
371
this.moduleInfoMap_[id].setUris(moduleUriMap[id]);
372
}
373
};
374
375
376
/**
377
* Gets the application-specific module loader.
378
* @return {goog.module.AbstractModuleLoader} An object that has a
379
* loadModules(ids, moduleInfoMap, opt_successFn, opt_errFn,
380
* opt_timeoutFn, opt_forceReload) method.
381
*/
382
goog.module.ModuleManager.prototype.getLoader = function() {
383
return this.loader_;
384
};
385
386
387
/**
388
* Sets the application-specific module loader.
389
* @param {goog.module.AbstractModuleLoader} loader An object that has a
390
* loadModules(ids, moduleInfoMap, opt_successFn, opt_errFn,
391
* opt_timeoutFn, opt_forceReload) method.
392
*/
393
goog.module.ModuleManager.prototype.setLoader = function(loader) {
394
this.loader_ = loader;
395
};
396
397
398
/**
399
* Gets the module context to use to initialize the module.
400
* @return {Object} The context.
401
*/
402
goog.module.ModuleManager.prototype.getModuleContext = function() {
403
return this.moduleContext_;
404
};
405
406
407
/**
408
* Sets the module context to use to initialize the module.
409
* @param {Object} context The context.
410
*/
411
goog.module.ModuleManager.prototype.setModuleContext = function(context) {
412
this.moduleContext_ = context;
413
this.maybeFinishBaseLoad_();
414
};
415
416
417
/**
418
* Determines if the ModuleManager is active
419
* @return {boolean} TRUE iff the ModuleManager is active (i.e., not idle).
420
*/
421
goog.module.ModuleManager.prototype.isActive = function() {
422
return this.loadingModuleIds_.length > 0;
423
};
424
425
426
/**
427
* Determines if the ModuleManager is user active
428
* @return {boolean} TRUE iff the ModuleManager is user active (i.e., not idle).
429
*/
430
goog.module.ModuleManager.prototype.isUserActive = function() {
431
return this.userInitiatedLoadingModuleIds_.length > 0;
432
};
433
434
435
/**
436
* Dispatches an ACTIVE or IDLE event if necessary.
437
* @private
438
*/
439
goog.module.ModuleManager.prototype.dispatchActiveIdleChangeIfNeeded_ =
440
function() {
441
var lastActive = this.lastActive_;
442
var active = this.isActive();
443
if (active != lastActive) {
444
this.executeCallbacks_(
445
active ? goog.module.ModuleManager.CallbackType.ACTIVE :
446
goog.module.ModuleManager.CallbackType.IDLE);
447
448
// Flip the last active value.
449
this.lastActive_ = active;
450
}
451
452
// Check if the module manager is user active i.e., there are user initiated
453
// modules being loaded or queued up to be loaded.
454
var userLastActive = this.userLastActive_;
455
var userActive = this.isUserActive();
456
if (userActive != userLastActive) {
457
this.executeCallbacks_(
458
userActive ? goog.module.ModuleManager.CallbackType.USER_ACTIVE :
459
goog.module.ModuleManager.CallbackType.USER_IDLE);
460
461
// Flip the last user active value.
462
this.userLastActive_ = userActive;
463
}
464
};
465
466
467
/**
468
* Preloads a module after a short delay.
469
*
470
* @param {string} id The id of the module to preload.
471
* @param {number=} opt_timeout The number of ms to wait before adding the
472
* module id to the loading queue (defaults to 0 ms). Note that the module
473
* will be loaded asynchronously regardless of the value of this parameter.
474
* @return {!goog.async.Deferred} A deferred object.
475
*/
476
goog.module.ModuleManager.prototype.preloadModule = function(id, opt_timeout) {
477
var d = new goog.async.Deferred();
478
window.setTimeout(
479
goog.bind(this.addLoadModule_, this, id, d), opt_timeout || 0);
480
return d;
481
};
482
483
484
/**
485
* Prefetches a JavaScript module and its dependencies, which means that the
486
* module will be downloaded, but not evaluated. To complete the module load,
487
* the caller should also call load or execOnLoad after prefetching the module.
488
*
489
* @param {string} id The id of the module to prefetch.
490
*/
491
goog.module.ModuleManager.prototype.prefetchModule = function(id) {
492
var moduleInfo = this.getModuleInfo(id);
493
if (moduleInfo.isLoaded() || this.isModuleLoading(id)) {
494
throw Error('Module load already requested: ' + id);
495
} else if (this.batchModeEnabled_) {
496
throw Error('Modules prefetching is not supported in batch mode');
497
} else {
498
var idWithDeps = this.getNotYetLoadedTransitiveDepIds_(id);
499
for (var i = 0; i < idWithDeps.length; i++) {
500
this.loader_.prefetchModule(
501
idWithDeps[i], this.moduleInfoMap_[idWithDeps[i]]);
502
}
503
}
504
};
505
506
507
/**
508
* Loads a single module for use with a given deferred.
509
*
510
* @param {string} id The id of the module to load.
511
* @param {goog.async.Deferred} d A deferred object.
512
* @private
513
*/
514
goog.module.ModuleManager.prototype.addLoadModule_ = function(id, d) {
515
var moduleInfo = this.getModuleInfo(id);
516
if (moduleInfo.isLoaded()) {
517
d.callback(this.moduleContext_);
518
return;
519
}
520
521
this.registerModuleLoadCallbacks_(id, moduleInfo, false, d);
522
if (!this.isModuleLoading(id)) {
523
this.loadModulesOrEnqueue_([id]);
524
}
525
};
526
527
528
/**
529
* Loads a list of modules or, if some other module is currently being loaded,
530
* appends the ids to the queue of requested module ids. Registers callbacks a
531
* module that is currently loading and returns a fired deferred for a module
532
* that is already loaded.
533
*
534
* @param {Array<string>} ids The id of the module to load.
535
* @param {boolean=} opt_userInitiated If the load is a result of a user action.
536
* @return {!Object<string, !goog.async.Deferred>} A mapping from id (String)
537
* to deferred objects that will callback or errback when the load for that
538
* id is finished.
539
* @private
540
*/
541
goog.module.ModuleManager.prototype.loadModulesOrEnqueueIfNotLoadedOrLoading_ =
542
function(ids, opt_userInitiated) {
543
var uniqueIds = [];
544
goog.array.removeDuplicates(ids, uniqueIds);
545
var idsToLoad = [];
546
var deferredMap = {};
547
for (var i = 0; i < uniqueIds.length; i++) {
548
var id = uniqueIds[i];
549
var moduleInfo = this.getModuleInfo(id);
550
if (!moduleInfo) {
551
throw new Error('Unknown module: ' + id);
552
}
553
var d = new goog.async.Deferred();
554
deferredMap[id] = d;
555
if (moduleInfo.isLoaded()) {
556
d.callback(this.moduleContext_);
557
} else {
558
this.registerModuleLoadCallbacks_(id, moduleInfo, !!opt_userInitiated, d);
559
if (!this.isModuleLoading(id)) {
560
idsToLoad.push(id);
561
}
562
}
563
}
564
565
// If there are ids to load, load them, otherwise, they are all loading or
566
// loaded.
567
if (idsToLoad.length > 0) {
568
this.loadModulesOrEnqueue_(idsToLoad);
569
}
570
return deferredMap;
571
};
572
573
574
/**
575
* Registers the callbacks and handles logic if it is a user initiated module
576
* load.
577
*
578
* @param {string} id The id of the module to possibly load.
579
* @param {!goog.module.ModuleInfo} moduleInfo The module identifier for the
580
* given id.
581
* @param {boolean} userInitiated If the load was user initiated.
582
* @param {goog.async.Deferred} d A deferred object.
583
* @private
584
*/
585
goog.module.ModuleManager.prototype.registerModuleLoadCallbacks_ = function(
586
id, moduleInfo, userInitiated, d) {
587
moduleInfo.registerCallback(d.callback, d);
588
moduleInfo.registerErrback(function(err) { d.errback(Error(err)); });
589
// If it's already loading, we don't have to do anything besides handle
590
// if it was user initiated
591
if (this.isModuleLoading(id)) {
592
if (userInitiated) {
593
goog.log.info(
594
this.logger_, 'User initiated module already loading: ' + id);
595
this.addUserInitiatedLoadingModule_(id);
596
this.dispatchActiveIdleChangeIfNeeded_();
597
}
598
} else {
599
if (userInitiated) {
600
goog.log.info(this.logger_, 'User initiated module load: ' + id);
601
this.addUserInitiatedLoadingModule_(id);
602
} else {
603
goog.log.info(this.logger_, 'Initiating module load: ' + id);
604
}
605
}
606
};
607
608
609
/**
610
* Initiates loading of a list of modules or, if a module is currently being
611
* loaded, appends the modules to the queue of requested module ids.
612
*
613
* The caller should verify that the requested modules are not already loaded or
614
* loading. {@link #loadModulesOrEnqueueIfNotLoadedOrLoading_} is a more lenient
615
* alternative to this method.
616
*
617
* @param {Array<string>} ids The ids of the modules to load.
618
* @private
619
*/
620
goog.module.ModuleManager.prototype.loadModulesOrEnqueue_ = function(ids) {
621
// With concurrent loading we always just send off the request.
622
if (this.concurrentLoadingEnabled_) {
623
// For now we wait for initial modules to have downloaded as this puts the
624
// loader in a good state for calculating the needed deps of additional
625
// loads.
626
// TODO(user): Make this wait unnecessary.
627
this.initialModulesLoaded_.addCallback(
628
goog.bind(this.loadModules_, this, ids));
629
} else {
630
if (goog.array.isEmpty(this.loadingModuleIds_)) {
631
this.loadModules_(ids);
632
} else {
633
this.requestedModuleIdsQueue_.push(ids);
634
this.dispatchActiveIdleChangeIfNeeded_();
635
}
636
}
637
};
638
639
640
/**
641
* Gets the amount of delay to wait before sending a request for more modules.
642
* If a certain module request fails, we backoff a little bit and try again.
643
* @return {number} Delay, in ms.
644
* @private
645
*/
646
goog.module.ModuleManager.prototype.getBackOff_ = function() {
647
// 5 seconds after one error, 20 seconds after 2.
648
return Math.pow(this.consecutiveFailures_, 2) * 5000;
649
};
650
651
652
/**
653
* Loads a list of modules and any of their not-yet-loaded prerequisites.
654
* If batch mode is enabled, the prerequisites will be loaded together with the
655
* requested modules and all requested modules will be loaded at the same time.
656
*
657
* The caller should verify that the requested modules are not already loaded
658
* and that no modules are currently loading before calling this method.
659
*
660
* @param {Array<string>} ids The ids of the modules to load.
661
* @param {boolean=} opt_isRetry If the load is a retry of a previous load
662
* attempt.
663
* @param {boolean=} opt_forceReload Whether to bypass cache while loading the
664
* module.
665
* @private
666
*/
667
goog.module.ModuleManager.prototype.loadModules_ = function(
668
ids, opt_isRetry, opt_forceReload) {
669
if (!opt_isRetry) {
670
this.consecutiveFailures_ = 0;
671
}
672
673
// Not all modules may be loaded immediately if batch mode is not enabled.
674
var idsToLoadImmediately = this.processModulesForLoad_(ids);
675
676
goog.log.info(this.logger_, 'Loading module(s): ' + idsToLoadImmediately);
677
this.loadingModuleIds_ = idsToLoadImmediately;
678
679
if (this.batchModeEnabled_) {
680
this.requestedLoadingModuleIds_ = ids;
681
} else {
682
// If batch mode is disabled, we treat each dependency load as a separate
683
// load.
684
this.requestedLoadingModuleIds_ = goog.array.clone(idsToLoadImmediately);
685
}
686
687
// Dispatch an active/idle change if needed.
688
this.dispatchActiveIdleChangeIfNeeded_();
689
690
if (goog.array.isEmpty(idsToLoadImmediately)) {
691
// All requested modules and deps have been either loaded already or have
692
// already been requested.
693
return;
694
}
695
696
this.requestedModuleIds_.push.apply(
697
this.requestedModuleIds_, idsToLoadImmediately);
698
699
var loadFn = goog.bind(
700
this.loader_.loadModules, this.loader_,
701
goog.array.clone(idsToLoadImmediately), this.moduleInfoMap_, null,
702
goog.bind(
703
this.handleLoadError_, this, this.requestedLoadingModuleIds_,
704
idsToLoadImmediately),
705
goog.bind(this.handleLoadTimeout_, this), !!opt_forceReload);
706
707
var delay = this.getBackOff_();
708
if (delay) {
709
window.setTimeout(loadFn, delay);
710
} else {
711
loadFn();
712
}
713
};
714
715
716
/**
717
* Processes a list of module ids for loading. Checks if any of the modules are
718
* already loaded and then gets transitive deps. Queues any necessary modules
719
* if batch mode is not enabled. Returns the list of ids that should be loaded.
720
*
721
* @param {Array<string>} ids The ids that need to be loaded.
722
* @return {!Array<string>} The ids to load, including dependencies.
723
* @throws {Error} If the module is already loaded.
724
* @private
725
*/
726
goog.module.ModuleManager.prototype.processModulesForLoad_ = function(ids) {
727
for (var i = 0; i < ids.length; i++) {
728
var moduleInfo = this.moduleInfoMap_[ids[i]];
729
if (moduleInfo.isLoaded()) {
730
throw Error('Module already loaded: ' + ids[i]);
731
}
732
}
733
734
// Build a list of the ids of this module and any of its not-yet-loaded
735
// prerequisite modules in dependency order.
736
var idsWithDeps = [];
737
for (var i = 0; i < ids.length; i++) {
738
idsWithDeps =
739
idsWithDeps.concat(this.getNotYetLoadedTransitiveDepIds_(ids[i]));
740
}
741
goog.array.removeDuplicates(idsWithDeps);
742
743
if (!this.batchModeEnabled_ && idsWithDeps.length > 1) {
744
var idToLoad = idsWithDeps.shift();
745
goog.log.info(
746
this.logger_, 'Must load ' + idToLoad + ' module before ' + ids);
747
748
// Insert the requested module id and any other not-yet-loaded prereqs
749
// that it has at the front of the queue.
750
var queuedModules =
751
goog.array.map(idsWithDeps, function(id) { return [id]; });
752
this.requestedModuleIdsQueue_ =
753
queuedModules.concat(this.requestedModuleIdsQueue_);
754
return [idToLoad];
755
} else {
756
return idsWithDeps;
757
}
758
};
759
760
761
/**
762
* Builds a list of the ids of the not-yet-loaded modules that a particular
763
* module transitively depends on, including itself.
764
*
765
* @param {string} id The id of a not-yet-loaded module.
766
* @return {!Array<string>} An array of module ids in dependency order that's
767
* guaranteed to end with the provided module id.
768
* @private
769
*/
770
goog.module.ModuleManager.prototype.getNotYetLoadedTransitiveDepIds_ = function(
771
id) {
772
// NOTE(user): We want the earliest occurrence of a module, not the first
773
// dependency we find. Therefore we strip duplicates at the end rather than
774
// during. See the tests for concrete examples.
775
var ids = [];
776
if (!goog.array.contains(this.requestedModuleIds_, id)) {
777
ids.push(id);
778
}
779
var depIds = goog.array.clone(this.getModuleInfo(id).getDependencies());
780
while (depIds.length) {
781
var depId = depIds.pop();
782
if (!this.getModuleInfo(depId).isLoaded() &&
783
!goog.array.contains(this.requestedModuleIds_, depId)) {
784
ids.unshift(depId);
785
// We need to process direct dependencies first.
786
Array.prototype.unshift.apply(
787
depIds, this.getModuleInfo(depId).getDependencies());
788
}
789
}
790
goog.array.removeDuplicates(ids);
791
return ids;
792
};
793
794
795
/**
796
* If we are still loading the base module, consider the load complete.
797
* @private
798
*/
799
goog.module.ModuleManager.prototype.maybeFinishBaseLoad_ = function() {
800
if (this.currentlyLoadingModule_ == this.baseModuleInfo_) {
801
this.currentlyLoadingModule_ = null;
802
var error =
803
this.baseModuleInfo_.onLoad(goog.bind(this.getModuleContext, this));
804
if (error) {
805
this.dispatchModuleLoadFailed_(
806
goog.module.ModuleManager.FailureType.INIT_ERROR);
807
}
808
809
this.dispatchActiveIdleChangeIfNeeded_();
810
}
811
};
812
813
814
/**
815
* Records that a module was loaded. Also initiates loading the next module if
816
* any module requests are queued. This method is called by code that is
817
* generated and appended to each dynamic module's code at compilation time.
818
*
819
* @param {string} id A module id.
820
*/
821
goog.module.ModuleManager.prototype.setLoaded = function(id) {
822
if (this.isDisposed()) {
823
goog.log.warning(
824
this.logger_, 'Module loaded after module manager was disposed: ' + id);
825
return;
826
}
827
828
goog.log.info(this.logger_, 'Module loaded: ' + id);
829
830
var error =
831
this.moduleInfoMap_[id].onLoad(goog.bind(this.getModuleContext, this));
832
if (error) {
833
this.dispatchModuleLoadFailed_(
834
goog.module.ModuleManager.FailureType.INIT_ERROR);
835
}
836
837
// Remove the module id from the user initiated set if it existed there.
838
goog.array.remove(this.userInitiatedLoadingModuleIds_, id);
839
840
// Remove the module id from the loading modules if it exists there.
841
goog.array.remove(this.loadingModuleIds_, id);
842
843
if (goog.array.isEmpty(this.loadingModuleIds_)) {
844
// No more modules are currently being loaded (e.g. arriving later in the
845
// same HTTP response), so proceed to load the next module in the queue.
846
this.loadNextModules_();
847
}
848
849
if (this.lastInitialModuleId_ && id == this.lastInitialModuleId_) {
850
if (!this.initialModulesLoaded_.hasFired()) {
851
this.initialModulesLoaded_.callback();
852
}
853
}
854
855
// Dispatch an active/idle change if needed.
856
this.dispatchActiveIdleChangeIfNeeded_();
857
};
858
859
860
/**
861
* Gets whether a module is currently loading or in the queue, waiting to be
862
* loaded.
863
* @param {string} id A module id.
864
* @return {boolean} TRUE iff the module is loading.
865
*/
866
goog.module.ModuleManager.prototype.isModuleLoading = function(id) {
867
if (goog.array.contains(this.loadingModuleIds_, id)) {
868
return true;
869
}
870
for (var i = 0; i < this.requestedModuleIdsQueue_.length; i++) {
871
if (goog.array.contains(this.requestedModuleIdsQueue_[i], id)) {
872
return true;
873
}
874
}
875
return false;
876
};
877
878
879
/**
880
* Requests that a function be called once a particular module is loaded.
881
* Client code can use this method to safely call into modules that may not yet
882
* be loaded. For consistency, this method always calls the function
883
* asynchronously -- even if the module is already loaded. Initiates loading of
884
* the module if necessary, unless opt_noLoad is true.
885
*
886
* @param {string} moduleId A module id.
887
* @param {Function} fn Function to execute when the module has loaded.
888
* @param {Object=} opt_handler Optional handler under whose scope to execute
889
* the callback.
890
* @param {boolean=} opt_noLoad TRUE iff not to initiate loading of the module.
891
* @param {boolean=} opt_userInitiated TRUE iff the loading of the module was
892
* user initiated.
893
* @param {boolean=} opt_preferSynchronous TRUE iff the function should be
894
* executed synchronously if the module has already been loaded.
895
* @return {!goog.module.ModuleLoadCallback} A callback wrapper that exposes
896
* an abort and execute method.
897
*/
898
goog.module.ModuleManager.prototype.execOnLoad = function(
899
moduleId, fn, opt_handler, opt_noLoad, opt_userInitiated,
900
opt_preferSynchronous) {
901
var moduleInfo = this.moduleInfoMap_[moduleId];
902
var callbackWrapper;
903
904
if (moduleInfo.isLoaded()) {
905
goog.log.info(this.logger_, moduleId + ' module already loaded');
906
// Call async so that code paths don't change between loaded and unloaded
907
// cases.
908
callbackWrapper = new goog.module.ModuleLoadCallback(fn, opt_handler);
909
if (opt_preferSynchronous) {
910
callbackWrapper.execute(this.moduleContext_);
911
} else {
912
window.setTimeout(goog.bind(callbackWrapper.execute, callbackWrapper), 0);
913
}
914
} else if (this.isModuleLoading(moduleId)) {
915
goog.log.info(this.logger_, moduleId + ' module already loading');
916
callbackWrapper = moduleInfo.registerCallback(fn, opt_handler);
917
if (opt_userInitiated) {
918
goog.log.info(
919
this.logger_, 'User initiated module already loading: ' + moduleId);
920
this.addUserInitiatedLoadingModule_(moduleId);
921
this.dispatchActiveIdleChangeIfNeeded_();
922
}
923
} else {
924
goog.log.info(this.logger_, 'Registering callback for module: ' + moduleId);
925
callbackWrapper = moduleInfo.registerCallback(fn, opt_handler);
926
if (!opt_noLoad) {
927
if (opt_userInitiated) {
928
goog.log.info(this.logger_, 'User initiated module load: ' + moduleId);
929
this.addUserInitiatedLoadingModule_(moduleId);
930
}
931
goog.log.info(this.logger_, 'Initiating module load: ' + moduleId);
932
this.loadModulesOrEnqueue_([moduleId]);
933
}
934
}
935
return callbackWrapper;
936
};
937
938
939
/**
940
* Loads a module, returning a goog.async.Deferred for keeping track of the
941
* result.
942
*
943
* @param {string} moduleId A module id.
944
* @param {boolean=} opt_userInitiated If the load is a result of a user action.
945
* @return {goog.async.Deferred} A deferred object.
946
*/
947
goog.module.ModuleManager.prototype.load = function(
948
moduleId, opt_userInitiated) {
949
return this.loadModulesOrEnqueueIfNotLoadedOrLoading_(
950
[moduleId], opt_userInitiated)[moduleId];
951
};
952
953
954
/**
955
* Loads a list of modules, returning a goog.async.Deferred for keeping track of
956
* the result.
957
*
958
* @param {Array<string>} moduleIds A list of module ids.
959
* @param {boolean=} opt_userInitiated If the load is a result of a user action.
960
* @return {!Object<string, !goog.async.Deferred>} A mapping from id (String)
961
* to deferred objects that will callback or errback when the load for that
962
* id is finished.
963
*/
964
goog.module.ModuleManager.prototype.loadMultiple = function(
965
moduleIds, opt_userInitiated) {
966
return this.loadModulesOrEnqueueIfNotLoadedOrLoading_(
967
moduleIds, opt_userInitiated);
968
};
969
970
971
/**
972
* Ensures that the module with the given id is listed as a user-initiated
973
* module that is being loaded. This method guarantees that a module will never
974
* get listed more than once.
975
* @param {string} id Identifier of the module.
976
* @private
977
*/
978
goog.module.ModuleManager.prototype.addUserInitiatedLoadingModule_ = function(
979
id) {
980
if (!goog.array.contains(this.userInitiatedLoadingModuleIds_, id)) {
981
this.userInitiatedLoadingModuleIds_.push(id);
982
}
983
};
984
985
986
/**
987
* Method called just before a module code is loaded.
988
* @param {string} id Identifier of the module.
989
*/
990
goog.module.ModuleManager.prototype.beforeLoadModuleCode = function(id) {
991
this.loadTracer_ =
992
goog.debug.Trace.startTracer('Module Load: ' + id, 'Module Load');
993
if (this.currentlyLoadingModule_) {
994
goog.log.error(
995
this.logger_, 'beforeLoadModuleCode called with module "' + id +
996
'" while module "' + this.currentlyLoadingModule_.getId() +
997
'" is loading');
998
}
999
this.currentlyLoadingModule_ = this.getModuleInfo(id);
1000
};
1001
1002
1003
/**
1004
* Method called just after module code is loaded
1005
* @param {string} id Identifier of the module.
1006
*/
1007
goog.module.ModuleManager.prototype.afterLoadModuleCode = function(id) {
1008
if (!this.currentlyLoadingModule_ ||
1009
id != this.currentlyLoadingModule_.getId()) {
1010
goog.log.error(
1011
this.logger_, 'afterLoadModuleCode called with module "' + id +
1012
'" while loading module "' +
1013
(this.currentlyLoadingModule_ &&
1014
this.currentlyLoadingModule_.getId()) +
1015
'"');
1016
}
1017
this.currentlyLoadingModule_ = null;
1018
goog.debug.Trace.stopTracer(this.loadTracer_);
1019
};
1020
1021
1022
/**
1023
* Register an initialization callback for the currently loading module. This
1024
* should only be called by script that is executed during the evaluation of
1025
* a module's javascript. This is almost equivalent to calling the function
1026
* inline, but ensures that all the code from the currently loading module
1027
* has been loaded. This makes it cleaner and more robust than calling the
1028
* function inline.
1029
*
1030
* If this function is called from the base module (the one that contains
1031
* the module manager code), the callback is held until #setAllModuleInfo
1032
* is called, or until #setModuleContext is called, whichever happens first.
1033
*
1034
* @param {Function} fn A callback function that takes a single argument
1035
* which is the module context.
1036
* @param {Object=} opt_handler Optional handler under whose scope to execute
1037
* the callback.
1038
*/
1039
goog.module.ModuleManager.prototype.registerInitializationCallback = function(
1040
fn, opt_handler) {
1041
if (!this.currentlyLoadingModule_) {
1042
goog.log.error(this.logger_, 'No module is currently loading');
1043
} else {
1044
this.currentlyLoadingModule_.registerEarlyCallback(fn, opt_handler);
1045
}
1046
};
1047
1048
1049
/**
1050
* Register a late initialization callback for the currently loading module.
1051
* Callbacks registered via this function are executed similar to
1052
* {@see registerInitializationCallback}, but they are fired after all
1053
* initialization callbacks are called.
1054
*
1055
* @param {Function} fn A callback function that takes a single argument
1056
* which is the module context.
1057
* @param {Object=} opt_handler Optional handler under whose scope to execute
1058
* the callback.
1059
*/
1060
goog.module.ModuleManager.prototype.registerLateInitializationCallback =
1061
function(fn, opt_handler) {
1062
if (!this.currentlyLoadingModule_) {
1063
goog.log.error(this.logger_, 'No module is currently loading');
1064
} else {
1065
this.currentlyLoadingModule_.registerCallback(fn, opt_handler);
1066
}
1067
};
1068
1069
1070
/**
1071
* Sets the constructor to use for the module object for the currently
1072
* loading module. The constructor should derive from
1073
* {@see goog.module.BaseModule}.
1074
* @param {Function} fn The constructor function.
1075
*/
1076
goog.module.ModuleManager.prototype.setModuleConstructor = function(fn) {
1077
if (!this.currentlyLoadingModule_) {
1078
goog.log.error(this.logger_, 'No module is currently loading');
1079
return;
1080
}
1081
this.currentlyLoadingModule_.setModuleConstructor(fn);
1082
};
1083
1084
1085
/**
1086
* The possible reasons for a module load failure callback being fired.
1087
* @enum {number}
1088
*/
1089
goog.module.ModuleManager.FailureType = {
1090
/** 401 Status. */
1091
UNAUTHORIZED: 0,
1092
1093
/** Error status (not 401) returned multiple times. */
1094
CONSECUTIVE_FAILURES: 1,
1095
1096
/** Request timeout. */
1097
TIMEOUT: 2,
1098
1099
/** 410 status, old code gone. */
1100
OLD_CODE_GONE: 3,
1101
1102
/** The onLoad callbacks failed. */
1103
INIT_ERROR: 4
1104
};
1105
1106
1107
/**
1108
* Handles a module load failure.
1109
*
1110
* @param {!Array<string>} requestedLoadingModuleIds Modules ids that were
1111
* requested in failed request. Does not included calculated dependencies.
1112
* @param {!Array<string>} requestedModuleIdsWithDeps All module ids requested
1113
* in the failed request including all dependencies.
1114
* @param {?number} status The error status.
1115
* @private
1116
*/
1117
goog.module.ModuleManager.prototype.handleLoadError_ = function(
1118
requestedLoadingModuleIds, requestedModuleIdsWithDeps, status) {
1119
this.consecutiveFailures_++;
1120
// Module manager was not designed to be reentrant. Reinstate the instance
1121
// var with actual value when request failed (Other requests may have
1122
// started already.)
1123
this.requestedLoadingModuleIds_ = requestedLoadingModuleIds;
1124
// Pretend we never requested the failed modules.
1125
goog.array.forEach(
1126
requestedModuleIdsWithDeps,
1127
goog.partial(goog.array.remove, this.requestedModuleIds_), this);
1128
1129
if (status == 401) {
1130
// The user is not logged in. They've cleared their cookies or logged out
1131
// from another window.
1132
goog.log.info(this.logger_, 'Module loading unauthorized');
1133
this.dispatchModuleLoadFailed_(
1134
goog.module.ModuleManager.FailureType.UNAUTHORIZED);
1135
// Drop any additional module requests.
1136
this.requestedModuleIdsQueue_.length = 0;
1137
} else if (status == 410) {
1138
// The requested module js is old and not available.
1139
this.requeueBatchOrDispatchFailure_(
1140
goog.module.ModuleManager.FailureType.OLD_CODE_GONE);
1141
this.loadNextModules_();
1142
} else if (this.consecutiveFailures_ >= 3) {
1143
goog.log.info(
1144
this.logger_,
1145
'Aborting after failure to load: ' + this.loadingModuleIds_);
1146
this.requeueBatchOrDispatchFailure_(
1147
goog.module.ModuleManager.FailureType.CONSECUTIVE_FAILURES);
1148
this.loadNextModules_();
1149
} else {
1150
goog.log.info(
1151
this.logger_,
1152
'Retrying after failure to load: ' + this.loadingModuleIds_);
1153
var forceReload =
1154
status == goog.module.ModuleManager.CORRUPT_RESPONSE_STATUS_CODE;
1155
this.loadModules_(this.requestedLoadingModuleIds_, true, forceReload);
1156
}
1157
};
1158
1159
1160
/**
1161
* Handles a module load timeout.
1162
* @private
1163
*/
1164
goog.module.ModuleManager.prototype.handleLoadTimeout_ = function() {
1165
goog.log.info(
1166
this.logger_, 'Aborting after timeout: ' + this.loadingModuleIds_);
1167
this.requeueBatchOrDispatchFailure_(
1168
goog.module.ModuleManager.FailureType.TIMEOUT);
1169
this.loadNextModules_();
1170
};
1171
1172
1173
/**
1174
* Requeues batch loads that had more than one requested module
1175
* (i.e. modules that were not included as dependencies) as separate loads or
1176
* if there was only one requested module, fails that module with the received
1177
* cause.
1178
* @param {goog.module.ModuleManager.FailureType} cause The reason for the
1179
* failure.
1180
* @private
1181
*/
1182
goog.module.ModuleManager.prototype.requeueBatchOrDispatchFailure_ = function(
1183
cause) {
1184
// The load failed, so if there are more than one requested modules, then we
1185
// need to retry each one as a separate load. Otherwise, if there is only one
1186
// requested module, remove it and its dependencies from the queue.
1187
if (this.requestedLoadingModuleIds_.length > 1) {
1188
var queuedModules = goog.array.map(
1189
this.requestedLoadingModuleIds_, function(id) { return [id]; });
1190
this.requestedModuleIdsQueue_ =
1191
queuedModules.concat(this.requestedModuleIdsQueue_);
1192
} else {
1193
this.dispatchModuleLoadFailed_(cause);
1194
}
1195
};
1196
1197
1198
/**
1199
* Handles when a module load failed.
1200
* @param {goog.module.ModuleManager.FailureType} cause The reason for the
1201
* failure.
1202
* @private
1203
*/
1204
goog.module.ModuleManager.prototype.dispatchModuleLoadFailed_ = function(
1205
cause) {
1206
var failedIds = this.requestedLoadingModuleIds_;
1207
this.loadingModuleIds_.length = 0;
1208
// If any pending modules depend on the id that failed,
1209
// they need to be removed from the queue.
1210
var idsToCancel = [];
1211
for (var i = 0; i < this.requestedModuleIdsQueue_.length; i++) {
1212
var dependentModules = goog.array.filter(
1213
this.requestedModuleIdsQueue_[i],
1214
/**
1215
* Returns true if the requestedId has dependencies on the modules that
1216
* just failed to load.
1217
* @param {string} requestedId The module to check for dependencies.
1218
* @return {boolean} True if the module depends on failed modules.
1219
*/
1220
function(requestedId) {
1221
var requestedDeps =
1222
this.getNotYetLoadedTransitiveDepIds_(requestedId);
1223
return goog.array.some(failedIds, function(id) {
1224
return goog.array.contains(requestedDeps, id);
1225
});
1226
},
1227
this);
1228
goog.array.extend(idsToCancel, dependentModules);
1229
}
1230
1231
// Also insert the ids that failed to load as ids to cancel.
1232
for (var i = 0; i < failedIds.length; i++) {
1233
goog.array.insert(idsToCancel, failedIds[i]);
1234
}
1235
1236
// Remove ids to cancel from the queues.
1237
for (var i = 0; i < idsToCancel.length; i++) {
1238
for (var j = 0; j < this.requestedModuleIdsQueue_.length; j++) {
1239
goog.array.remove(this.requestedModuleIdsQueue_[j], idsToCancel[i]);
1240
}
1241
goog.array.remove(this.userInitiatedLoadingModuleIds_, idsToCancel[i]);
1242
}
1243
1244
// Call the functions for error notification.
1245
var errorCallbacks =
1246
this.callbackMap_[goog.module.ModuleManager.CallbackType.ERROR];
1247
if (errorCallbacks) {
1248
for (var i = 0; i < errorCallbacks.length; i++) {
1249
var callback = errorCallbacks[i];
1250
for (var j = 0; j < idsToCancel.length; j++) {
1251
callback(
1252
goog.module.ModuleManager.CallbackType.ERROR, idsToCancel[j],
1253
cause);
1254
}
1255
}
1256
}
1257
1258
// Call the errbacks on the module info.
1259
for (var i = 0; i < failedIds.length; i++) {
1260
if (this.moduleInfoMap_[failedIds[i]]) {
1261
this.moduleInfoMap_[failedIds[i]].onError(cause);
1262
}
1263
}
1264
1265
// Clear the requested loading module ids.
1266
this.requestedLoadingModuleIds_.length = 0;
1267
1268
this.dispatchActiveIdleChangeIfNeeded_();
1269
};
1270
1271
1272
/**
1273
* Loads the next modules on the queue.
1274
* @private
1275
*/
1276
goog.module.ModuleManager.prototype.loadNextModules_ = function() {
1277
while (this.requestedModuleIdsQueue_.length) {
1278
// Remove modules that are already loaded.
1279
var nextIds = goog.array.filter(
1280
this.requestedModuleIdsQueue_.shift(),
1281
function(id) { return !this.getModuleInfo(id).isLoaded(); }, this);
1282
if (nextIds.length > 0) {
1283
this.loadModules_(nextIds);
1284
return;
1285
}
1286
}
1287
1288
// Dispatch an active/idle change if needed.
1289
this.dispatchActiveIdleChangeIfNeeded_();
1290
};
1291
1292
1293
/**
1294
* The function to call if the module manager is in error.
1295
* @param
1296
* {goog.module.ModuleManager.CallbackType|Array<goog.module.ModuleManager.CallbackType>}
1297
* types
1298
* The callback type.
1299
* @param {Function} fn The function to register as a callback.
1300
*/
1301
goog.module.ModuleManager.prototype.registerCallback = function(types, fn) {
1302
if (!goog.isArray(types)) {
1303
types = [types];
1304
}
1305
1306
for (var i = 0; i < types.length; i++) {
1307
this.registerCallback_(types[i], fn);
1308
}
1309
};
1310
1311
1312
/**
1313
* Register a callback for the specified callback type.
1314
* @param {goog.module.ModuleManager.CallbackType} type The callback type.
1315
* @param {Function} fn The callback function.
1316
* @private
1317
*/
1318
goog.module.ModuleManager.prototype.registerCallback_ = function(type, fn) {
1319
var callbackMap = this.callbackMap_;
1320
if (!callbackMap[type]) {
1321
callbackMap[type] = [];
1322
}
1323
callbackMap[type].push(fn);
1324
};
1325
1326
1327
/**
1328
* Call the callback functions of the specified type.
1329
* @param {goog.module.ModuleManager.CallbackType} type The callback type.
1330
* @private
1331
*/
1332
goog.module.ModuleManager.prototype.executeCallbacks_ = function(type) {
1333
var callbacks = this.callbackMap_[type];
1334
for (var i = 0; callbacks && i < callbacks.length; i++) {
1335
callbacks[i](type);
1336
}
1337
};
1338
1339
1340
/** @override */
1341
goog.module.ModuleManager.prototype.disposeInternal = function() {
1342
goog.module.ModuleManager.base(this, 'disposeInternal');
1343
1344
// Dispose of each ModuleInfo object.
1345
goog.disposeAll(
1346
goog.object.getValues(this.moduleInfoMap_), this.baseModuleInfo_);
1347
this.moduleInfoMap_ = null;
1348
this.loadingModuleIds_ = null;
1349
this.requestedLoadingModuleIds_ = null;
1350
this.userInitiatedLoadingModuleIds_ = null;
1351
this.requestedModuleIdsQueue_ = null;
1352
this.callbackMap_ = null;
1353
};
1354
1355