Browse Source

Check state when returning from a promise

Steven Silvester 8 năm trước cách đây
mục cha
commit
8c9392c9ee

+ 1 - 1
src/application/shell.ts

@@ -326,7 +326,7 @@ class ApplicationShell extends Widget {
     }
     this._database = database;
     this._database.fetch().then(saved => {
-      if (!saved) {
+      if (this.isDisposed && !saved) {
         return;
       }
 

+ 3 - 0
src/completer/handler.ts

@@ -117,6 +117,9 @@ class CellCompleterHandler implements IDisposable {
     let request = this.getState(position);
 
     return this._kernel.requestComplete(content).then(msg => {
+      if (this.isDisposed) {
+        return;
+      }
       this.onReply(pending, request, msg);
     });
   }

+ 7 - 1
src/docmanager/savehandler.ts

@@ -133,7 +133,7 @@ class SaveHandler implements IDisposable {
     // Make sure the file has not changed on disk.
     let promise = this._manager.contents.get(context.path);
     promise.then(model => {
-      if (context.contentsModel &&
+      if (!this.isDisposed && context.contentsModel &&
           model.last_modified !== context.contentsModel.last_modified) {
         return this._timeConflict(model.last_modified);
       }
@@ -163,6 +163,9 @@ class SaveHandler implements IDisposable {
       title: 'File Changed', body, okText: 'OVERWRITE',
       buttons: [cancelButton, { text: 'REVERT' }, okButton]
     }).then(result => {
+      if (this.isDisposed) {
+        return;
+      }
       this._inDialog = false;
       if (result.text === 'OVERWRITE') {
         return this._finishSave();
@@ -178,6 +181,9 @@ class SaveHandler implements IDisposable {
   private _finishSave(): Promise<void> {
     let start = new Date().getTime();
     return this._context.save().then(() => {
+      if (this.isDisposed) {
+        return;
+      }
       let duration = new Date().getTime() - start;
       // New save interval: higher of 10x save duration or min interval.
       this._interval = Math.max(10 * duration, this._minInterval);

+ 6 - 0
src/docmanager/widgetmanager.ts

@@ -246,6 +246,9 @@ class DocumentWidgetManager implements IDisposable {
       return;
     }
     context.listCheckpoints().then(checkpoints => {
+      if (widget.isDisposed) {
+        return;
+      }
       let last = checkpoints[checkpoints.length - 1];
       let checkpoint = last ? dateTime(last.last_modified) : 'None';
       widget.title.caption = (
@@ -267,6 +270,9 @@ class DocumentWidgetManager implements IDisposable {
   protected onClose(widget: Widget): Promise<boolean> {
     // Handle dirty state.
     return this._maybeClose(widget).then(result => {
+      if (widget.isDisposed) {
+        return true;
+      }
       if (result) {
         this._closeGuard = true;
         widget.close();

+ 24 - 3
src/docregistry/context.ts

@@ -177,6 +177,9 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
    */
   startDefaultKernel(): Promise<Kernel.IKernel> {
     return this.ready.then(() => {
+      if (this.isDisposed) {
+        return;
+      }
       let model = this.model;
       let name = findKernel(
         model.defaultKernelName,
@@ -209,6 +212,9 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
         this._session = null;
         return session.shutdown().then(() => {
           session.dispose();
+          if (this.isDisposed) {
+            return;
+          }
           this.kernelChanged.emit(null);
           return void 0;
         });
@@ -242,6 +248,9 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
 
     let promise = this._manager.contents.save(path, options);
     return promise.then(value => {
+      if (this.isDisposed) {
+        return;
+      }
       model.dirty = false;
       this._updateContentsModel(value);
 
@@ -262,7 +271,7 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
    */
   saveAs(): Promise<void> {
     return Private.getSavePath(this._path).then(newPath => {
-      if (!newPath) {
+      if (this.isDisposed || !newPath) {
         return;
       }
       this._path = newPath;
@@ -274,6 +283,9 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
           kernelName: session.kernel.name
         };
         return this._startSession(options).then(() => {
+          if (this.isDisposed) {
+            return;
+          }
           return this.save();
         });
       }
@@ -293,6 +305,9 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
     let path = this._path;
     let model = this._model;
     return this._manager.contents.get(path, opts).then(contents => {
+      if (this.isDisposed) {
+        return;
+      }
       if (contents.format === 'json') {
         model.fromJSON(contents.content);
       } else {
@@ -336,7 +351,7 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
       return contents.restoreCheckpoint(path, checkpointId);
     }
     return this.listCheckpoints().then(checkpoints => {
-      if (!checkpoints.length) {
+      if (this.isDisposed || !checkpoints.length) {
         return;
       }
       checkpointId = checkpoints[checkpoints.length - 1].id;
@@ -398,6 +413,9 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
    */
   private _startSession(options: Session.IOptions): Promise<Kernel.IKernel> {
     return this._manager.sessions.startNew(options).then(session => {
+      if (this.isDisposed) {
+        return;
+      }
       if (this._session) {
         this._session.dispose();
       }
@@ -470,10 +488,13 @@ class Context<T extends DocumentRegistry.IModel> implements DocumentRegistry.ICo
     this._isPopulated = true;
     // Add a checkpoint if none exists.
     return this.listCheckpoints().then(checkpoints => {
-      if (!checkpoints) {
+      if (!this.isDisposed && !checkpoints) {
         return this.createCheckpoint();
       }
     }).then(() => {
+      if (this.isDisposed) {
+        return;
+      }
       this._isReady = true;
       this._populatedPromise.resolve(void 0);
     });

+ 1 - 1
src/docregistry/kernelactions.ts

@@ -32,7 +32,7 @@ function restartKernel(kernel: Kernel.IKernel, host?: HTMLElement): Promise<bool
     body: 'Do you want to restart the current kernel? All variables will be lost.',
     buttons: [cancelButton, warnButton]
   }).then(result => {
-    if (result.text === 'OK') {
+    if (!kernel.isDisposed && result.text === 'OK') {
       return kernel.restart().then(() => { return true; });
     } else {
       return false;

+ 3 - 1
src/filebrowser/browser.ts

@@ -197,7 +197,9 @@ class FileBrowser extends Widget {
   createNew(options: Contents.ICreateOptions): Promise<Widget> {
     let model = this.model;
     return model.newUntitled(options).then(contents => {
-      return this._buttons.createNew(contents.path);
+      if (!this.isDisposed) {
+        return this._buttons.createNew(contents.path);
+      }
     });
   }
 

+ 1 - 1
src/filebrowser/buttons.ts

@@ -515,7 +515,7 @@ namespace Private {
       body: `"${file.name}" already exists, overwrite?`
     };
     return showDialog(options).then(button => {
-      if (button.text !== 'Ok') {
+      if (widget.isDisposed || button.text !== 'Ok') {
         return;
       }
       return widget.model.upload(file, true);

+ 6 - 3
src/filebrowser/crumbs.ts

@@ -260,6 +260,7 @@ class BreadCrumbs extends Widget {
       return;
     }
     let path = BREAD_CRUMB_PATHS[index];
+    let model = this._model;
 
     // Move all of the items.
     let promises: Promise<any>[] = [];
@@ -277,9 +278,11 @@ class BreadCrumbs extends Widget {
             okText: 'OVERWRITE'
           };
           return showDialog(options).then(button => {
-            if (button.text === 'OVERWRITE') {
-              return this._model.deleteFile(newPath).then(() => {
-                return this._model.rename(name, newPath);
+            if (!model.isDisposed && button.text === 'OVERWRITE') {
+              return model.deleteFile(newPath).then(() => {
+                if (!model.isDisposed) {
+                  return this._model.rename(name, newPath);
+                }
               });
             }
           });

+ 11 - 2
src/filebrowser/listing.ts

@@ -376,7 +376,7 @@ class DirListing extends Widget {
         okText: 'DELETE',
         buttons: [cancelButton, deleteButton]
       }).then(result => {
-        if (result.text === 'DELETE') {
+        if (!this.isDisposed && result.text === 'DELETE') {
           return this._delete(names);
         }
       });
@@ -1079,6 +1079,9 @@ class DirListing extends Widget {
   private _selectItemByName(name: string): Promise<void> {
     // Make sure the file is available.
     return this.model.cd('.').then(() => {
+      if (this.isDisposed) {
+        return;
+      }
       let items = this._sortedItems;
       let index = findIndex(items, value => value.name === name);
       this._selectItem(index, false);
@@ -1177,10 +1180,16 @@ class DirListing extends Widget {
       if (newName === original) {
         return original;
       }
+      if (this.isDisposed) {
+        return;
+      }
       return renameFile(this._model, original, newName).catch(error => {
         utils.showErrorMessage('Rename Error', error);
         return original;
       }).then(() => {
+        if (this.isDisposed) {
+          return;
+        }
         this._selectItemByName(newName);
         return newName;
       });
@@ -1234,7 +1243,7 @@ class DirListing extends Widget {
   private _onFileChanged(sender: FileBrowserModel, args: Contents.IChangedArgs) {
     if (args.type === 'new') {
       this._selectItemByName(args.newValue.name).then(() => {
-        if (args.newValue === 'directory') {
+        if (!this.isDisposed && args.newValue === 'directory') {
           this._doRename();
         }
       });

+ 6 - 0
src/filebrowser/model.ts

@@ -170,6 +170,9 @@ class FileBrowserModel implements IDisposable, IPathTracker {
     }
     let manager = this._manager;
     this._pending = manager.contents.get(newValue, options).then(contents => {
+      if (this.isDisposed) {
+        return;
+      }
       this._handleContents(contents);
       this._pendingPath = null;
       if (oldValue !== newValue) {
@@ -297,6 +300,9 @@ class FileBrowserModel implements IDisposable, IPathTracker {
       let msg = `"${file.name}" already exists`;
       throw new Error(msg);
     }, () => {
+      if (this.isDisposed) {
+        return;
+      }
       return this._upload(file);
     });
   }

+ 6 - 0
src/notebook/notebook/actions.ts

@@ -400,6 +400,9 @@ namespace NotebookActions {
       promises.push(Private.runCell(widget, child, kernel));
     });
     return Promise.all(promises).then(results => {
+      if (widget.isDisposed) {
+        return false;
+      }
       // Post an update request.
       widget.update();
       for (let result of results) {
@@ -914,6 +917,9 @@ namespace Private {
     case 'code':
       if (kernel) {
         return (child as CodeCellWidget).execute(kernel).then(reply => {
+          if (child.isDisposed) {
+            return false;
+          }
           if (reply && reply.content.status === 'ok') {
             let content = reply.content as KernelMessage.IExecuteOkReply;
             if (content.payload && content.payload.length) {

+ 3 - 1
src/notebook/notebook/default-toolbar.ts

@@ -88,7 +88,9 @@ namespace ToolbarItems {
       className: TOOLBAR_SAVE_CLASS,
       onClick: () => {
         panel.context.save().then(() => {
-          return panel.context.createCheckpoint();
+          if (!panel.isDisposed) {
+            return panel.context.createCheckpoint();
+          }
         });
       },
       tooltip: 'Save the notebook contents and create checkpoint'

+ 6 - 0
src/notebook/notebook/panel.ts

@@ -303,6 +303,9 @@ class NotebookPanel extends Widget {
     // Clear the cells when the context is initially populated.
     if (!newValue.isReady) {
       newValue.ready.then(() => {
+        if (this.isDisposed) {
+          return;
+        }
         let model = newValue.model;
         // Clear the undo state of the cells.
         if (model) {
@@ -347,6 +350,9 @@ class NotebookPanel extends Widget {
    */
   private _updateSpec(kernel: Kernel.IKernel): void {
     kernel.getSpec().then(spec => {
+      if (this.isDisposed) {
+        return;
+      }
       let specCursor = this.model.getMetadata('kernelspec');
       specCursor.setValue({
         name: kernel.name,

+ 3 - 0
src/notebook/notebook/widget.ts

@@ -1303,6 +1303,9 @@ class Notebook extends StaticNotebook {
     document.removeEventListener('mousemove', this, true);
     document.removeEventListener('mouseup', this, true);
     this._drag.start(clientX, clientY).then(action => {
+      if (this.isDisposed) {
+        return;
+      }
       this._drag = null;
       each(toremove, widget => { widget.removeClass(DROP_SOURCE_CLASS); });
       if (action === 'none') {

+ 3 - 0
src/terminal/index.ts

@@ -85,6 +85,9 @@ class TerminalWidget extends Widget {
       return;
     }
     this._session.ready.then(() => {
+      if (this.isDisposed) {
+        return;
+      }
       this._session.messageReceived.connect(this._onMessage, this);
       this.title.label = `Terminal ${this._session.name}`;
       this._setSessionSize();