浏览代码

Merge pull request #1520 from blink1073/dispose-audit

Audit of dispose methods
Afshin Darian 8 年之前
父节点
当前提交
12d081814b

+ 3 - 5
src/codemirror/editor.ts

@@ -145,19 +145,18 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
    * Tests whether the editor is disposed.
    * Tests whether the editor is disposed.
    */
    */
   get isDisposed(): boolean {
   get isDisposed(): boolean {
-    return this._isDisposed;
+    return this._editor === null;
   }
   }
 
 
   /**
   /**
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._editor === null) {
       return;
       return;
     }
     }
-    this._isDisposed = true;
-    this._model = null;
     this._editor = null;
     this._editor = null;
+    this._model = null;
     this._keydownHandlers.clear();
     this._keydownHandlers.clear();
     clearSignalData(this);
     clearSignalData(this);
   }
   }
@@ -654,7 +653,6 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
 
 
   private _model: CodeEditor.IModel;
   private _model: CodeEditor.IModel;
   private _editor: CodeMirror.Editor;
   private _editor: CodeMirror.Editor;
-  private _isDisposed = false;
   protected selectionMarkers: { [key: string]: CodeMirror.TextMarker[] | undefined } = {};
   protected selectionMarkers: { [key: string]: CodeMirror.TextMarker[] | undefined } = {};
   private _keydownHandlers = new Vector<CodeEditor.KeydownHandler>();
   private _keydownHandlers = new Vector<CodeEditor.KeydownHandler>();
   private _changeGuard = false;
   private _changeGuard = false;

+ 14 - 16
src/commandlinker/commandlinker.ts

@@ -48,7 +48,7 @@ const ICommandLinker = new Token<ICommandLinker>('jupyter.services.command-linke
  * A helper class to generate clickables that execute commands.
  * A helper class to generate clickables that execute commands.
  */
  */
 export
 export
-interface ICommandLinker {
+interface ICommandLinker extends IDisposable {
   /**
   /**
    * Connect a command/argument pair to a given node so that when it is clicked,
    * Connect a command/argument pair to a given node so that when it is clicked,
    * the command will execute.
    * the command will execute.
@@ -111,7 +111,7 @@ interface ICommandLinker {
  * execute registered commands with pre-populated arguments.
  * execute registered commands with pre-populated arguments.
  */
  */
 export
 export
-class CommandLinker implements ICommandLinker, IDisposable {
+class CommandLinker implements ICommandLinker {
   /**
   /**
    * Instantiate a new command linker.
    * Instantiate a new command linker.
    */
    */
@@ -124,7 +124,18 @@ class CommandLinker implements ICommandLinker, IDisposable {
    * Test whether the linker is disposed.
    * Test whether the linker is disposed.
    */
    */
   get isDisposed(): boolean {
   get isDisposed(): boolean {
-    return this._isDisposed;
+    return this._commands === null;
+  }
+
+  /**
+   * Dispose of the resources held by the linker.
+   */
+  dispose(): void {
+    if (this._commands === null) {
+      return;
+    }
+    this._commands = null;
+    document.body.removeEventListener('click', this);
   }
   }
 
 
   /**
   /**
@@ -175,18 +186,6 @@ class CommandLinker implements ICommandLinker, IDisposable {
     return node;
     return node;
   }
   }
 
 
-  /**
-   * Dispose of the resources held by the linker.
-   */
-  dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
-    this._isDisposed = true;
-    this._commands = null;
-    document.body.removeEventListener('click', this);
-  }
-
   /**
   /**
    * Handle the DOM events for the command linker helper class.
    * Handle the DOM events for the command linker helper class.
    *
    *
@@ -256,7 +255,6 @@ class CommandLinker implements ICommandLinker, IDisposable {
   }
   }
 
 
   private _commands: CommandRegistry = null;
   private _commands: CommandRegistry = null;
-  private _isDisposed = false;
 }
 }
 
 
 
 

+ 12 - 11
src/common/instancetracker.ts

@@ -42,7 +42,7 @@ import {
  * An object that tracks widget instances.
  * An object that tracks widget instances.
  */
  */
 export
 export
-interface IInstanceTracker<T extends Widget> {
+interface IInstanceTracker<T extends Widget> extends IDisposable {
   /**
   /**
    * A signal emitted when the current widget changes.
    * A signal emitted when the current widget changes.
    *
    *
@@ -126,13 +126,6 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
     return this._tracker.currentWidget;
     return this._tracker.currentWidget;
   }
   }
 
 
-  /**
-   * Test whether the tracker is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._isDisposed;
-  }
-
   /**
   /**
    * The number of widgets held by the tracker.
    * The number of widgets held by the tracker.
    */
    */
@@ -178,15 +171,24 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
     return promise || Promise.resolve(void 0);
     return promise || Promise.resolve(void 0);
   }
   }
 
 
+  /**
+   * Test whether the tracker is disposed.
+   */
+  get isDisposed(): boolean {
+    return this._tracker === null;
+  }
+
   /**
   /**
    * Dispose of the resources held by the tracker.
    * Dispose of the resources held by the tracker.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._tracker === null) {
       return;
       return;
     }
     }
-    this._isDisposed = true;
+    let tracker = this._tracker;
+    this._tracker = null;
     clearSignalData(this);
     clearSignalData(this);
+    tracker.dispose();
   }
   }
 
 
   /**
   /**
@@ -345,7 +347,6 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
     }
     }
   }
   }
 
 
-  private _isDisposed = false;
   private _restore: InstanceTracker.IRestoreOptions<T> = null;
   private _restore: InstanceTracker.IRestoreOptions<T> = null;
   private _tracker = new FocusTracker<T>();
   private _tracker = new FocusTracker<T>();
 }
 }

+ 2 - 2
src/common/observablevector.ts

@@ -296,12 +296,12 @@ class ObservableVector<T> extends Vector<T> implements IObservableVector<T> {
    * Dispose of the resources held by the vector.
    * Dispose of the resources held by the vector.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._isDisposed) {
       return;
       return;
     }
     }
     this._isDisposed = true;
     this._isDisposed = true;
-    this.clear();
     clearSignalData(this);
     clearSignalData(this);
+    this.clear();
   }
   }
 
 
   /**
   /**

+ 8 - 18
src/common/vdom.ts

@@ -44,6 +44,13 @@ class VDomModel implements IVDomModel {
    */
    */
   readonly stateChanged: ISignal<this, void>;
   readonly stateChanged: ISignal<this, void>;
 
 
+  /**
+   * Test whether the model is disposed.
+   */
+  get isDisposed(): boolean {
+    return this._isDisposed;
+  }
+
   /**
   /**
    * Dispose the model.
    * Dispose the model.
    */
    */
@@ -55,13 +62,6 @@ class VDomModel implements IVDomModel {
     clearSignalData(this);
     clearSignalData(this);
   }
   }
 
 
-  /**
-   * Test whether the model is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._isDisposed;
-  }
-
   private _isDisposed = false;
   private _isDisposed = false;
 }
 }
 
 
@@ -105,22 +105,12 @@ abstract class VDomWidget<T extends IVDomModel> extends Widget {
     return this._model;
     return this._model;
   }
   }
 
 
-  /**
-   * Test whether the widget is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._model === null;
-  }
-
   /**
   /**
    * Dispose this widget.
    * Dispose this widget.
    */
    */
   dispose() {
   dispose() {
-    if (this.isDisposed) {
-      return;
-    }
-    super.dispose();
     this._model = null;
     this._model = null;
+    super.dispose();
   }
   }
 
 
   /**
   /**

+ 0 - 3
src/completer/handler.ts

@@ -81,9 +81,6 @@ class CompletionHandler implements IDisposable {
    * Dispose of the resources used by the handler.
    * Dispose of the resources used by the handler.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
     this._completer = null;
     this._completer = null;
     this._kernel = null;
     this._kernel = null;
     this._editor = null;
     this._editor = null;

+ 1 - 2
src/completer/model.ts

@@ -144,12 +144,11 @@ class CompleterModel implements CompleterWidget.IModel {
    */
    */
   dispose(): void {
   dispose(): void {
     // Do nothing if already disposed.
     // Do nothing if already disposed.
-    if (this.isDisposed) {
+    if (this._isDisposed) {
       return;
       return;
     }
     }
     this._isDisposed = true;
     this._isDisposed = true;
     clearSignalData(this);
     clearSignalData(this);
-    this._reset();
   }
   }
 
 
   /**
   /**

+ 11 - 12
src/console/foreign.ts

@@ -39,13 +39,6 @@ class ForeignHandler implements IDisposable {
     this._enabled = value;
     this._enabled = value;
   }
   }
 
 
-  /**
-   * Test whether the handler is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._isDisposed;
-  }
-
   /**
   /**
    * The kernel used by the foreign handler.
    * The kernel used by the foreign handler.
    */
    */
@@ -76,17 +69,24 @@ class ForeignHandler implements IDisposable {
     return this._parent;
     return this._parent;
   }
   }
 
 
+  /**
+   * Test whether the handler is disposed.
+   */
+  get isDisposed(): boolean {
+    return this._cells === null;
+  }
+
   /**
   /**
    * Dispose the resources held by the handler.
    * Dispose the resources held by the handler.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._cells === null) {
       return;
       return;
     }
     }
-    this._isDisposed = true;
-    this.kernel = null;
-    this._cells.clear();
+    let cells = this._cells;
     this._cells = null;
     this._cells = null;
+    this._kernel = null;
+    cells.clear();
   }
   }
 
 
   /**
   /**
@@ -157,7 +157,6 @@ class ForeignHandler implements IDisposable {
 
 
   private _cells = new Map<string, CodeCellWidget>();
   private _cells = new Map<string, CodeCellWidget>();
   private _enabled = true;
   private _enabled = true;
-  private _isDisposed = false;
   private _kernel: Kernel.IKernel = null;
   private _kernel: Kernel.IKernel = null;
   private _parent: ForeignHandler.IReceiver = null;
   private _parent: ForeignHandler.IReceiver = null;
   private _factory: () => CodeCellWidget = null;
   private _factory: () => CodeCellWidget = null;

+ 9 - 9
src/console/history.ts

@@ -98,13 +98,6 @@ class ConsoleHistory implements IConsoleHistory {
     }
     }
   }
   }
 
 
-  /**
-   * Get whether the console history manager is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._history === null;
-  }
-
   /**
   /**
    * The current kernel supplying navigation history.
    * The current kernel supplying navigation history.
    */
    */
@@ -157,15 +150,22 @@ class ConsoleHistory implements IConsoleHistory {
     return this._placeholder;
     return this._placeholder;
   }
   }
 
 
+  /**
+   * Get whether the console history manager is disposed.
+   */
+  get isDisposed(): boolean {
+    return this._history === null;
+  }
+
   /**
   /**
    * Dispose of the resources held by the console history manager.
    * Dispose of the resources held by the console history manager.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._history == null) {
       return;
       return;
     }
     }
-    clearSignalData(this);
     this._history = null;
     this._history = null;
+    clearSignalData(this);
   }
   }
 
 
   /**
   /**

+ 9 - 11
src/console/widget.ts

@@ -238,27 +238,25 @@ class CodeConsole extends Widget {
     }
     }
   }
   }
 
 
-  /**
-   * Test whether the widget is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._foreignHandler === null;
-  }
-
   /**
   /**
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose() {
   dispose() {
     // Do nothing if already disposed.
     // Do nothing if already disposed.
-    if (this.isDisposed) {
+    if (this._foreignHandler === null) {
       return;
       return;
     }
     }
-    this._foreignHandler.dispose();
+    let foreignHandler = this._foreignHandler;
+    let history = this._history;
+    let cells = this._cells;
     this._foreignHandler = null;
     this._foreignHandler = null;
-    this._history.dispose();
     this._history = null;
     this._history = null;
-    this._cells.clear();
     this._cells = null;
     this._cells = null;
+
+    foreignHandler.dispose();
+    history.dispose();
+    cells.clear();
+
     super.dispose();
     super.dispose();
   }
   }
 
 

+ 1 - 12
src/csvwidget/table.ts

@@ -4,7 +4,7 @@
 import * as dsv from 'd3-dsv';
 import * as dsv from 'd3-dsv';
 
 
 import {
 import {
-  clearSignalData, defineSignal, ISignal
+  defineSignal, ISignal
 } from 'phosphor/lib/core/signaling';
 } from 'phosphor/lib/core/signaling';
 
 
 import {
 import {
@@ -80,17 +80,6 @@ class CSVModel extends VDomModel {
     this.stateChanged.emit(void 0);
     this.stateChanged.emit(void 0);
   }
   }
 
 
-  /**
-   * Dispose this model.
-   */
-  dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
-    super.dispose();
-    clearSignalData(this);
-  }
-
   /**
   /**
    * Parse the content using the model's delimiter.
    * Parse the content using the model's delimiter.
    *
    *

+ 0 - 11
src/csvwidget/toolbar.ts

@@ -66,17 +66,6 @@ class CSVToolbar extends Widget {
     return this.node.getElementsByTagName('select')[0];
     return this.node.getElementsByTagName('select')[0];
   }
   }
 
 
-  /**
-   * Dispose of the resources held by the toolbar.
-   */
-  dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
-    super.dispose();
-    clearSignalData(this);
-  }
-
   /**
   /**
    * Handle the DOM events for the widget.
    * Handle the DOM events for the widget.
    *
    *

+ 11 - 12
src/csvwidget/widget.ts

@@ -94,24 +94,23 @@ class CSVWidget extends Widget {
    * Dispose of the resources used by the widget.
    * Dispose of the resources used by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._model === null) {
       return;
       return;
     }
     }
-
-    super.dispose();
-    disconnectReceiver(this);
-
-    this._model.dispose();
+    let model = this._model;
+    let table = this._table;
+    let toolbar = this._toolbar;
+    let warning = this._warning;
     this._model = null;
     this._model = null;
-
-    this._table.dispose();
     this._table = null;
     this._table = null;
-
-    this._toolbar.dispose();
     this._toolbar = null;
     this._toolbar = null;
-
-    this._warning.dispose();
     this._warning = null;
     this._warning = null;
+
+    model.dispose();
+    table.dispose();
+    toolbar.dispose();
+    warning.dispose();
+    super.dispose();
   }
   }
 
 
   /**
   /**

+ 7 - 2
src/docmanager/manager.ts

@@ -25,6 +25,10 @@ import {
   AttachedProperty
   AttachedProperty
 } from 'phosphor/lib/core/properties';
 } from 'phosphor/lib/core/properties';
 
 
+import {
+  clearSignalData
+} from 'phosphor/lib/core/signaling';
+
 import {
 import {
   Token
   Token
 } from 'phosphor/lib/core/token';
 } from 'phosphor/lib/core/token';
@@ -109,15 +113,16 @@ class DocumentManager implements IDisposable {
    * Dispose of the resources held by the document manager.
    * Dispose of the resources held by the document manager.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._serviceManager === null) {
       return;
       return;
     }
     }
     this._serviceManager = null;
     this._serviceManager = null;
+    this._widgetManager = null;
+    clearSignalData(this);
     each(this._contexts, context => {
     each(this._contexts, context => {
       context.dispose();
       context.dispose();
     });
     });
     this._contexts.clear();
     this._contexts.clear();
-    this._widgetManager = null;
   }
   }
 
 
   /**
   /**

+ 2 - 2
src/docmanager/savehandler.ts

@@ -74,11 +74,11 @@ class SaveHandler implements IDisposable {
    * Dispose of the resources used by the save handler.
    * Dispose of the resources used by the save handler.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._context === null) {
       return;
       return;
     }
     }
-    clearTimeout(this._autosaveTimer);
     this._context = null;
     this._context = null;
+    clearTimeout(this._autosaveTimer);
     clearSignalData(this);
     clearSignalData(this);
   }
   }
 
 

+ 2 - 2
src/docmanager/widgetmanager.ts

@@ -75,11 +75,11 @@ class DocumentWidgetManager implements IDisposable {
    * Dispose of the resources used by the widget manager.
    * Dispose of the resources used by the widget manager.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._registry == null) {
       return;
       return;
     }
     }
-    disconnectReceiver(this);
     this._registry = null;
     this._registry = null;
+    disconnectReceiver(this);
   }
   }
 
 
   /**
   /**

+ 13 - 9
src/docregistry/context.ts

@@ -125,28 +125,32 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
   }
   }
 
 
   /**
   /**
-   * Test whether the context has been disposed (read-only).
+   * Test whether the context is disposed.
    */
    */
   get isDisposed(): boolean {
   get isDisposed(): boolean {
-    return this._manager === null;
+    return this._model === null;
   }
   }
 
 
   /**
   /**
    * Dispose of the resources held by the context.
    * Dispose of the resources held by the context.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._model == null) {
       return;
       return;
     }
     }
-    this.disposed.emit(void 0);
-    clearSignalData(this);
-    this._model.dispose();
+    let model = this._model;
+    let session = this._session;
+    this._model = null;
+    this._session = null;
     this._manager = null;
     this._manager = null;
     this._factory = null;
     this._factory = null;
-    if (this._session) {
-      this._session.dispose();
-      this._session = null;
+
+    model.dispose();
+    if (session) {
+      session.dispose();
     }
     }
+    this.disposed.emit(void 0);
+    clearSignalData(this);
   }
   }
 
 
   /**
   /**

+ 19 - 12
src/docregistry/registry.ts

@@ -22,7 +22,7 @@ import {
 } from 'phosphor/lib/core/disposable';
 } from 'phosphor/lib/core/disposable';
 
 
 import {
 import {
-  ISignal, defineSignal
+  ISignal, clearSignalData, defineSignal
 } from 'phosphor/lib/core/signaling';
 } from 'phosphor/lib/core/signaling';
 
 
 import {
 import {
@@ -62,7 +62,7 @@ interface IDocumentRegistry extends DocumentRegistry {}
  * The document registry.
  * The document registry.
  */
  */
 export
 export
-class DocumentRegistry {
+class DocumentRegistry implements IDisposable {
   /**
   /**
    * A signal emitted when the registry has changed.
    * A signal emitted when the registry has changed.
    */
    */
@@ -79,22 +79,29 @@ class DocumentRegistry {
    * Dispose of the resources held by the document registery.
    * Dispose of the resources held by the document registery.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._widgetFactories === null) {
       return;
       return;
     }
     }
-    for (let modelName in this._modelFactories) {
-      this._modelFactories[modelName].dispose();
-    }
+    let widgetFactories = this._widgetFactories;
+    let modelFactories = this._modelFactories;
+    let extenders = this._extenders;
+    this._widgetFactories = null;
     this._modelFactories = null;
     this._modelFactories = null;
-    for (let widgetName in this._widgetFactories) {
-      this._widgetFactories[widgetName].dispose();
+    this._extenders = null;
+
+    for (let modelName in modelFactories) {
+      modelFactories[modelName].dispose();
     }
     }
-    this._widgetFactories = null;
+    for (let widgetName in widgetFactories) {
+      widgetFactories[widgetName].dispose();
+    }
+    for (let widgetName in extenders) {
+      extenders[widgetName].clear();
+    }
+
     this._fileTypes.clear();
     this._fileTypes.clear();
     this._creators.clear();
     this._creators.clear();
-    for (let widgetName in this._extenders) {
-      this._extenders[widgetName].clear();
-    }
+    clearSignalData(this);
   }
   }
 
 
   /**
   /**

+ 9 - 10
src/filebrowser/model.ts

@@ -100,13 +100,6 @@ class FileBrowserModel implements IDisposable, IPathTracker {
     return this._model ? this._model.path : '';
     return this._model ? this._model.path : '';
   }
   }
 
 
-  /**
-   * Get whether the model is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._model === null;
-  }
-
   /**
   /**
    * Get the kernel spec models.
    * Get the kernel spec models.
    */
    */
@@ -114,20 +107,26 @@ class FileBrowserModel implements IDisposable, IPathTracker {
     return this._manager.sessions.specs;
     return this._manager.sessions.specs;
   }
   }
 
 
+  /**
+   * Get whether the model is disposed.
+   */
+  get isDisposed(): boolean {
+    return this._model === null;
+  }
   /**
   /**
    * Dispose of the resources held by the model.
    * Dispose of the resources held by the model.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._model === null) {
       return;
       return;
     }
     }
+    this._model = null;
+    this._manager = null;
     clearTimeout(this._timeoutId);
     clearTimeout(this._timeoutId);
     clearInterval(this._refreshId);
     clearInterval(this._refreshId);
     clearTimeout(this._blackoutId);
     clearTimeout(this._blackoutId);
-    this._model = null;
     this._sessions.clear();
     this._sessions.clear();
     this._items.clear();
     this._items.clear();
-    this._manager = null;
     clearSignalData(this);
     clearSignalData(this);
   }
   }
 
 

+ 0 - 3
src/imagewidget/widget.ts

@@ -71,9 +71,6 @@ class ImageWidget extends Widget {
    * Dispose of the resources used by the widget.
    * Dispose of the resources used by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
     this._context = null;
     this._context = null;
     super.dispose();
     super.dispose();
   }
   }

+ 4 - 4
src/inspector/handler.ts

@@ -93,18 +93,19 @@ class InspectionHandler implements IDisposable, Inspector.IInspectable {
    * This is a read-only property.
    * This is a read-only property.
    */
    */
   get isDisposed(): boolean {
   get isDisposed(): boolean {
-    return this._isDisposed;
+    return this._editor === null;
   }
   }
 
 
   /**
   /**
    * Dispose of the resources used by the handler.
    * Dispose of the resources used by the handler.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._editor === null) {
       return;
       return;
     }
     }
-    this._isDisposed = true;
     this._editor = null;
     this._editor = null;
+    this._kernel = null;
+    this._rendermime = null;
     this.disposed.emit(void 0);
     this.disposed.emit(void 0);
     clearSignalData(this);
     clearSignalData(this);
   }
   }
@@ -169,7 +170,6 @@ class InspectionHandler implements IDisposable, Inspector.IInspectable {
   }
   }
 
 
   private _editor: CodeEditor.IEditor = null;
   private _editor: CodeEditor.IEditor = null;
-  private _isDisposed = false;
   private _kernel: Kernel.IKernel = null;
   private _kernel: Kernel.IKernel = null;
   private _pending = 0;
   private _pending = 0;
   private _rendermime: RenderMime = null;
   private _rendermime: RenderMime = null;

+ 12 - 18
src/inspector/inspector.ts

@@ -150,17 +150,16 @@ class Inspector extends TabPanel implements IInspector {
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._items == null) {
       return;
       return;
     }
     }
-
-    // Dispose the inspector child items.
-    Object.keys(this._items).forEach(i => { this._items[i].dispose(); });
+    let items = this._items;
     this._items = null;
     this._items = null;
-
-    // Disconnect from source.
     this.source = null;
     this.source = null;
 
 
+    // Dispose the inspector child items.
+    Object.keys(items).forEach(i => { items[i].dispose(); });
+
     super.dispose();
     super.dispose();
   }
   }
 
 
@@ -406,21 +405,16 @@ class InspectorItem extends Panel {
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._toolbar === null) {
       return;
       return;
     }
     }
+    let toolbar = this._toolbar;
+    let history = this._history;
+    this._toolbar = null;
+    this._history = null;
 
 
-    clearSignalData(this);
-
-    if (this._history) {
-      this._history.forEach(widget => widget.dispose());
-      this._history = null;
-    }
-
-    if (this._toolbar) {
-      this._toolbar.dispose();
-    }
-
+    history.forEach(widget => widget.dispose());
+    toolbar.dispose();
     super.dispose();
     super.dispose();
   }
   }
 
 

+ 3 - 0
src/markdownwidget/widget.ts

@@ -75,6 +75,9 @@ class MarkdownWidget extends Widget {
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
+    if (this.isDisposed) {
+      return;
+    }
     this._monitor.dispose();
     this._monitor.dispose();
     super.dispose();
     super.dispose();
   }
   }

+ 0 - 11
src/notebook/common/undo.ts

@@ -103,21 +103,10 @@ class ObservableUndoableVector<T extends ISerializable> extends ObservableVector
     return this._index >= 0;
     return this._index >= 0;
   }
   }
 
 
-  /**
-   * Test whether the vector is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._factory === null;
-  }
-
   /**
   /**
    * Dispose of the resources held by the model.
    * Dispose of the resources held by the model.
    */
    */
   dispose(): void {
   dispose(): void {
-    // Do nothing if already disposed.
-    if (this.isDisposed) {
-      return;
-    }
     this._factory = null;
     this._factory = null;
     this._stack = null;
     this._stack = null;
     super.dispose();
     super.dispose();

+ 9 - 9
src/notebook/notebook/model.ts

@@ -177,23 +177,23 @@ class NotebookModel extends DocumentModel implements INotebookModel {
    */
    */
   dispose(): void {
   dispose(): void {
     // Do nothing if already disposed.
     // Do nothing if already disposed.
-    if (this.isDisposed) {
+    if (this._cells === null) {
       return;
       return;
     }
     }
     let cells = this._cells;
     let cells = this._cells;
-    cells.dispose();
-    clearSignalData(this);
+    let cursors = this._cursors;
+    this._cells = null;
+    this._cursors = null;
+    this._metadata = null;
+
     for (let i = 0; i < cells.length; i++) {
     for (let i = 0; i < cells.length; i++) {
       let cell = cells.at(i);
       let cell = cells.at(i);
       cell.dispose();
       cell.dispose();
     }
     }
-    cells.clear();
-    this._cells = null;
-    for (let key in this._cursors) {
-      this._cursors[key].dispose();
+    cells.dispose();
+    for (let key in cursors) {
+      cursors[key].dispose();
     }
     }
-    this._cursors = null;
-    this._metadata = null;
     super.dispose();
     super.dispose();
   }
   }
 
 

+ 8 - 5
src/notebook/notebook/panel.ts

@@ -233,15 +233,18 @@ class NotebookPanel extends Widget {
    * Dispose of the resources used by the widget.
    * Dispose of the resources used by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._completer === null) {
       return;
       return;
     }
     }
+    let completer = this._completer;
+    let completerHandler = this._completerHandler;
+    this._completer = null;
     this._context = null;
     this._context = null;
-    this.notebook.dispose();
-    this._completerHandler.dispose();
     this._completerHandler = null;
     this._completerHandler = null;
-    this._completer.dispose();
-    this._completer = null;
+
+    this.notebook.dispose();
+    completerHandler.dispose();
+    completer.dispose();
     this.inspectionHandler.dispose();
     this.inspectionHandler.dispose();
     super.dispose();
     super.dispose();
   }
   }

+ 1 - 1
src/notebook/notebook/widget.ts

@@ -767,7 +767,7 @@ class Notebook extends StaticNotebook {
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
+    if (this._activeCell === null) {
       return;
       return;
     }
     }
     this._activeCell = null;
     this._activeCell = null;

+ 0 - 10
src/notebook/notebook/widgetfactory.ts

@@ -68,16 +68,6 @@ class NotebookWidgetFactory extends ABCWidgetFactory<NotebookPanel, INotebookMod
    */
    */
   readonly mimeTypeService: IEditorMimeTypeService;
   readonly mimeTypeService: IEditorMimeTypeService;
 
 
-  /**
-   * Dispose of the resources used by the factory.
-   */
-  dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
-    super.dispose();
-  }
-
   /**
   /**
    * Create a new widget.
    * Create a new widget.
    *
    *

+ 0 - 8
src/notebook/output-area/widget.ts

@@ -279,10 +279,6 @@ class OutputAreaWidget extends Widget {
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose() {
   dispose() {
-    // Do nothing if already disposed.
-    if (this.isDisposed) {
-      return;
-    }
     this._model = null;
     this._model = null;
     super.dispose();
     super.dispose();
   }
   }
@@ -636,10 +632,6 @@ class OutputGutter extends Widget {
    * Dispose of the resources held by the widget.
    * Dispose of the resources held by the widget.
    */
    */
   dispose() {
   dispose() {
-    // Do nothing if already disposed.
-    if (this.isDisposed) {
-      return;
-    }
     this._dragData = null;
     this._dragData = null;
     this._drag = null;
     this._drag = null;
     super.dispose();
     super.dispose();

+ 1 - 4
src/notebook/tracker.ts

@@ -94,11 +94,8 @@ class NotebookTracker extends InstanceTracker<NotebookPanel> implements INoteboo
    * Dispose of the resources held by the tracker.
    * Dispose of the resources held by the tracker.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
-    super.dispose();
     this._activeCell = null;
     this._activeCell = null;
+    super.dispose();
   }
   }
 
 
   /**
   /**

+ 1 - 10
src/running/index.ts

@@ -182,24 +182,15 @@ class RunningSessions extends Widget {
     return this._renderer;
     return this._renderer;
   }
   }
 
 
-  /**
-   * Test whether the widget is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._manager === null;
-  }
-
   /**
   /**
    * Dispose of the resources used by the widget.
    * Dispose of the resources used by the widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
     this._manager = null;
     this._manager = null;
     this._runningSessions = null;
     this._runningSessions = null;
     this._runningTerminals = null;
     this._runningTerminals = null;
     this._renderer = null;
     this._renderer = null;
+    super.dispose();
   }
   }
 
 
   /**
   /**

+ 0 - 3
src/terminal/index.ts

@@ -155,9 +155,6 @@ class TerminalWidget extends Widget {
    * Dispose of the resources held by the terminal widget.
    * Dispose of the resources held by the terminal widget.
    */
    */
   dispose(): void {
   dispose(): void {
-    if (this.isDisposed) {
-      return;
-    }
     this._session = null;
     this._session = null;
     this._sheet = null;
     this._sheet = null;
     this._term = null;
     this._term = null;

+ 9 - 1
tutorial/patterns.md

@@ -56,7 +56,15 @@ pattern is used to ensure resources are freed and can be claimed by the
 Garbage Collector when no longer needed.  It should always be safe to
 Garbage Collector when no longer needed.  It should always be safe to
 `dispose()` of an object more than once.  Typically the object that
 `dispose()` of an object more than once.  Typically the object that
 creates another object is responsible for calling the dispose method
 creates another object is responsible for calling the dispose method
-of that object unless explicitly stated otherwise.
+of that object unless explicitly stated otherwise.  
+To mirror the pattern  of construction, `super.dispose()` should be called 
+last in the `dispose()` method if there is a parent class. 
+Make sure any signal connections are cleared in either the local or parent 
+`dispose()` method.  Use a sentinel value to guard against reentry, typically 
+by checking if an internal value is null, and then immediately setting the 
+value to null.  A subclass should never override the `isDisposed` getter,
+because it short-circuits the parent class getter.  The object should not
+be considered disposed until the base class `dispose()` method is called.
 
 
 
 
 ## Messages
 ## Messages