Path: blob/trunk/third_party/closure/goog/disposable/disposable.js
4209 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Implements the disposable interface.8*/910goog.provide('goog.Disposable');1112goog.require('goog.disposable.IDisposable');13goog.require('goog.dispose');14/**15* TODO(user): Remove this require.16* @suppress {extraRequire}17*/18goog.require('goog.disposeAll');1920goog.require('goog.utils');2122/**23* Class that provides the basic implementation for disposable objects. If your24* class holds references or resources that can't be collected by standard GC,25* it should extend this class or implement the disposable interface (defined26* in goog.disposable.IDisposable). See description of27* goog.disposable.IDisposable for examples of cleanup.28* @constructor29* @implements {goog.disposable.IDisposable}30*/31goog.Disposable = function() {32'use strict';33/**34* If monitoring the goog.Disposable instances is enabled, stores the creation35* stack trace of the Disposable instance.36* @type {string|undefined}37*/38this.creationStack;3940if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {41if (goog.Disposable.INCLUDE_STACK_ON_CREATION) {42this.creationStack = new Error().stack;43}44goog.Disposable.instances_[goog.utils.getUid(this)] = this;45}46// Support sealing47this.disposed_ = this.disposed_;48this.onDisposeCallbacks_ = this.onDisposeCallbacks_;49};505152/**53* @enum {number} Different monitoring modes for Disposable.54*/55goog.Disposable.MonitoringMode = {56/**57* No monitoring.58*/59OFF: 0,60/**61* Creating and disposing the goog.Disposable instances is monitored. All62* disposable objects need to call the `goog.Disposable` base63* constructor. The PERMANENT mode must be switched on before creating any64* goog.Disposable instances.65*/66PERMANENT: 1,67/**68* INTERACTIVE mode can be switched on and off on the fly without producing69* errors. It also doesn't warn if the disposable objects don't call the70* `goog.Disposable` base constructor.71*/72INTERACTIVE: 273};747576/**77* @define {number} The monitoring mode of the goog.Disposable78* instances. Default is OFF. Switching on the monitoring is only79* recommended for debugging because it has a significant impact on80* performance and memory usage. If switched off, the monitoring code81* compiles down to 0 bytes.82*/83goog.Disposable.MONITORING_MODE =84goog.define('goog.Disposable.MONITORING_MODE', 0);858687/**88* @define {boolean} Whether to attach creation stack to each created disposable89* instance; This is only relevant for when MonitoringMode != OFF.90*/91goog.Disposable.INCLUDE_STACK_ON_CREATION =92goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true);939495/**96* Maps the unique ID of every undisposed `goog.Disposable` object to97* the object itself.98* @type {!Object<number, !goog.Disposable>}99* @private100*/101goog.Disposable.instances_ = {};102103104/**105* @return {!Array<!goog.Disposable>} All `goog.Disposable` objects that106* haven't been disposed of.107*/108goog.Disposable.getUndisposedObjects = function() {109'use strict';110var ret = [];111for (var id in goog.Disposable.instances_) {112if (goog.Disposable.instances_.hasOwnProperty(id)) {113ret.push(goog.Disposable.instances_[Number(id)]);114}115}116return ret;117};118119120/**121* Clears the registry of undisposed objects but doesn't dispose of them.122*/123goog.Disposable.clearUndisposedObjects = function() {124'use strict';125goog.Disposable.instances_ = {};126};127128129/**130* Whether the object has been disposed of.131* @type {boolean}132* @private133*/134goog.Disposable.prototype.disposed_ = false;135136137/**138* Callbacks to invoke when this object is disposed.139* @type {Array<!Function>}140* @private141*/142goog.Disposable.prototype.onDisposeCallbacks_;143144145/**146* @return {boolean} Whether the object has been disposed of.147* @override148*/149goog.Disposable.prototype.isDisposed = function() {150'use strict';151return this.disposed_;152};153154155/**156* @return {boolean} Whether the object has been disposed of.157* @deprecated Use {@link #isDisposed} instead.158*/159goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;160161162/**163* Disposes of the object. If the object hasn't already been disposed of, calls164* {@link #disposeInternal}. Classes that extend `goog.Disposable` should165* override {@link #disposeInternal} in order to cleanup references, resources166* and other disposable objects. Reentrant.167*168* @return {void} Nothing.169* @override170*/171goog.Disposable.prototype.dispose = function() {172'use strict';173if (!this.disposed_) {174// Set disposed_ to true first, in case during the chain of disposal this175// gets disposed recursively.176this.disposed_ = true;177this.disposeInternal();178if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {179var uid = goog.utils.getUid(this);180if (goog.Disposable.MONITORING_MODE ==181goog.Disposable.MonitoringMode.PERMANENT &&182!goog.Disposable.instances_.hasOwnProperty(uid)) {183throw new Error(184this + ' did not call the goog.Disposable base ' +185'constructor or was disposed of after a clearUndisposedObjects ' +186'call');187}188if (goog.Disposable.MONITORING_MODE !=189goog.Disposable.MonitoringMode.OFF &&190this.onDisposeCallbacks_ && this.onDisposeCallbacks_.length > 0) {191throw new Error(192this + ' did not empty its onDisposeCallbacks queue. This ' +193'probably means it overrode dispose() or disposeInternal() ' +194'without calling the superclass\' method.');195}196delete goog.Disposable.instances_[uid];197}198}199};200201202/**203* Associates a disposable object with this object so that they will be disposed204* together.205* @param {goog.disposable.IDisposable} disposable that will be disposed when206* this object is disposed.207*/208goog.Disposable.prototype.registerDisposable = function(disposable) {209'use strict';210this.addOnDisposeCallback(goog.utils.partial(goog.dispose, disposable));211};212213214/**215* Invokes a callback function when this object is disposed. Callbacks are216* invoked in the order in which they were added. If a callback is added to217* an already disposed Disposable, it will be called immediately.218* @param {function(this:T):?} callback The callback function.219* @param {T=} opt_scope An optional scope to call the callback in.220* @template T221*/222goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {223'use strict';224if (this.disposed_) {225opt_scope !== undefined ? callback.call(opt_scope) : callback();226return;227}228if (!this.onDisposeCallbacks_) {229this.onDisposeCallbacks_ = [];230}231232this.onDisposeCallbacks_.push(233opt_scope !== undefined ? goog.utils.bind(callback, opt_scope) : callback);234};235236237/**238* Performs appropriate cleanup. See description of goog.disposable.IDisposable239* for examples. Classes that extend `goog.Disposable` should override this240* method. Not reentrant. To avoid calling it twice, it must only be called from241* the subclass' `disposeInternal` method. Everywhere else the public `dispose`242* method must be used. For example:243*244* <pre>245* mypackage.MyClass = function() {246* mypackage.MyClass.base(this, 'constructor');247* // Constructor logic specific to MyClass.248* ...249* };250* goog.inherits(mypackage.MyClass, goog.Disposable);251*252* mypackage.MyClass.prototype.disposeInternal = function() {253* // Dispose logic specific to MyClass.254* ...255* // Call superclass's disposeInternal at the end of the subclass's, like256* // in C++, to avoid hard-to-catch issues.257* mypackage.MyClass.base(this, 'disposeInternal');258* };259* </pre>260*261* @protected262*/263goog.Disposable.prototype.disposeInternal = function() {264'use strict';265if (this.onDisposeCallbacks_) {266while (this.onDisposeCallbacks_.length) {267this.onDisposeCallbacks_.shift()();268}269}270};271272273/**274* Returns True if we can verify the object is disposed.275* Calls `isDisposed` on the argument if it supports it. If obj276* is not an object with an isDisposed() method, return false.277* @param {*} obj The object to investigate.278* @return {boolean} True if we can verify the object is disposed.279*/280goog.Disposable.isDisposed = function(obj) {281'use strict';282if (obj && typeof obj.isDisposed == 'function') {283return obj.isDisposed();284}285return false;286};287288289